I'm trying to use JFugue 5.0.9 in my Java project to create *.midi files with it. While implementing JFugue's midi capabilities into my project that uses frequencies of a 24 tune makam piano, I realized it has some tune issues.
For example this code:
ChordProgression cp = new ChordProgression("I-III-IV-iv").setKey("E");
System.out.println(cp);
Player player = new Player();
player.play(cp);
should print
E4MAJ G#4MAJ A4MAJ A4MIN
on console as it's said here.
But prints
E4MAJ E4MAJ E4MAJ A4MIN
in my project. Yes, first three chords are same for some reason. They sound same also, of course.
Also, while using microtones like "m390", it doesn't sound exactly in that frequency.
In another file, in the main method I wrote this:
Player player = new Player();
player.play("A4 m440 m400 m390 m380 m370 m360");
I know that A4 and m440 are the same but as it's said here, A5 and m440 should sound same. But in my project A4 and m440 sound same but it's not exactly 440Hz. When I realized something goes wrong, I decided to use a tuning app and here are the frequencies it calculated respectively:
221.5 221.5 197.5 186.6 186.6 186.6 176.2
As you can see, it plays something very near A3 instead of a clear A4. But this is not all. It also sounds exactly same for m390, m380 and m370.
What exactly is wrong here? Any help would be appreciated.
A little note: I'm pretty sure it has nothing to do with my project. I tryed running the codes above in a brand new project, the same problems occured. And there's no problem with my system because my main project and any other softwares like SunVox, they all sound very good actually.
OK, I had a look at the source codes of JFugue 5.0.9 and here is what I got in ChordProgression.java:
/**
* Only converts Roman numerals I through VII, because that's all we need in music theory...
* VIII would be the octave and equal I!
*/
private int romanNumeralToIndex(String romanNumeral) {
String s = romanNumeral.toLowerCase();
if (s.startsWith("vii")) { return 6; }
else if (s.startsWith("vi")) { return 5; }
else if (s.startsWith("v")) { return 4; }
else if (s.startsWith("iv")) { return 3; }
else if (s.startsWith("iii")) { return 2; }
else if (s.startsWith("ii")) { return 1; }
else if (s.startsWith("i")) { return 0; }
else { return 0; }
}
A little laziness... :D One of the problems lies right here. If you use toLowerCase() method without specifying a locale, it causes some problems in runtime. In Turkish alphabet which I'm using right now lower case of I is "ı", not "i". So, the program converts my chords from "I-II-III" to "i-i-i" because as you can see there is no if statement for lower case I of Turkish alphabet (ı) and this leads it to return 0 as in the case of "i".
To solve this issue, we have to either delete lower case conversion and write all if statements for also upper case I's or set default locale to "en" to make sure it converts (upper case)I's to (lower case)i's. So, this should be used in the source:
Locale.setDefault(new Locale("en"));
Fortunately, JFugue is an open source software published under Apache 2.0.
This still doesn't explain why tunes sound wrong but now at least we know that these are totally different problems. Or maybe it seems so... I don't know. I will edit this answer if I ever find out an explanation or a solution for the rest.
Edit
Finally I figured out the problem with microtones by accident. I decided to look at microtone calculation functions in the source one more time.
In MicrotonePreprocessor class (which is in org.staccato package) there is a function named convertFrequencyToStaccato(). What this function does is convert frequency to midi note number and pitch bend value. At the 107th line, that code rounds semitone, octave and pitch values if calculated pitch value is very close to the next note:
// If we're close enough to the next note, just use the next note.
if (pitches >= 16380)
{
pitches = 0;
semitone += 1;
if (semitone == 12)
{
octave += 1;
semitone = 0;
}
}
The line where pitch is reset should be changed as:
pitches = 8192;
Because, you know, neutral pitch value is 8192. 0 (zero) is minimum pitch value and 16384 is maximum pitch value. At first, I thought the same way as the developer: "After 16384, it should be 0. That is okay. No problem here.". Then I said "What if I change pitch-reset value from 0 to 8192?". It worked. This was a beautiful perception error we both had. :D I'm really having a lot of laugh now.
This fixes the microtone issue. I can hear perfect intervals now! I feel happy and satisfied.
Edit2
I just wanted to share my further changes which results in better microtonal tunning:
if (pitches >= 12288)
{
int diff = 16384-pitches;
int applieddiff = 8192-diff;
pitches = applieddiff;
semitone += 1;
if (semitone == 12)
{
octave += 1;
semitone = 0;
}
}
This also helps use semitone (black) keys on a midi-board instead of only tone (white) keys with high pitch values. So, if you send the data to another software, it will detect all keys seperately. For example, there were no G and G# before, only G and G-with-high-pitch. These caused keys to stop eachother when note-on messages are sent simultaneously.
Related
I am trying to create a XSSFConditionalFormattingRule with a 3-scale coloring. Therefore I need to set the thresholds as well. Yet upon debugging I found that each XSSFConditionalFormattingThreshold throws an com.sun.jdi.InvocationException occurred invoking method. on their CTCfvo property, but only after calling rule.getColorScaleFormatting().setNumControlPoints(3);
My complete code is this:
CellRangeAddress[] regions = { CellRangeAddress.valueOf("Z2:Z" + (sheet.getLastRowNum() + 1)) };
XSSFConditionalFormattingRule rule = sheet.getSheetConditionalFormatting()
.createConditionalFormattingColorScaleRule();
XSSFConditionalFormattingThreshold thresh5 = rule.getColorScaleFormatting().createThreshold();
thresh5.setRangeType(RangeType.NUMBER);
thresh5.setValue(0.05);
XSSFConditionalFormattingThreshold thresh10 = rule.getColorScaleFormatting().createThreshold();
thresh10.setRangeType(RangeType.NUMBER);
thresh10.setValue(0.10);
XSSFConditionalFormattingThreshold thresh15 = rule.getColorScaleFormatting().createThreshold();
thresh15.setRangeType(RangeType.NUMBER);
thresh15.setValue(0.15);
rule.getColorScaleFormatting().setNumControlPoints(3);
rule.getColorScaleFormatting()
.setThresholds(new ConditionalFormattingThreshold[] { thresh5, thresh10, thresh15 });
XSSFColor colorGreen = new XSSFColor(IndexedColors.GREEN, colorMap);
XSSFColor colorYellow = new XSSFColor(IndexedColors.YELLOW, colorMap);
XSSFColor colorRed = new XSSFColor(IndexedColors.RED, colorMap);
rule.getColorScaleFormatting().setColors(new Color[] { colorGreen, colorYellow, colorRed });
sheet.getSheetConditionalFormatting().addConditionalFormatting(regions, rule);
And this the shortened stacktrace I get when execting the code above:
org.apache.xmlbeans.impl.values.XmlValueDisconnectedException at
org.apache.xmlbeans.impl.values.XmlObjectBase.check_orphaned(XmlObjectBase.java:1258)
at
org.apache.xmlbeans.impl.values.XmlObjectBase.newCursor(XmlObjectBase.java:286)
at
org.apache.xmlbeans.impl.values.XmlComplexContentImpl.arraySetterHelper(XmlComplexContentImpl.java:1124)
at
org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTColorScaleImpl.setCfvoArray(Unknown
Source) at
org.apache.poi.xssf.usermodel.XSSFColorScaleFormatting.setThresholds(XSSFColorScaleFormatting.java:85)
What causes the error I am seeing here? Is it a mistake when I create the XSSFConditionalFormattingThreshold? Or something entirely else?
I am using apache poi v4.0.0.
As stated in the question, the only occurences of this error was attributed to writing the workbook twice (SO question, bugzilla). So that got me wondering what I am doing wrong. I had no real idea where to start, as everything associated with the error has nothing to do with my problem.
My first look went to the documentation of void org.apache.poi.xssf.usermodel.XSSFColorScaleFormatting.setNumControlPoints(int num), which states the following:
Sets the number of control points to use to map the colours. Should
normally be 2 or 3.
After updating, you need to ensure that the Threshold count and Color
count match
The second part caught my eye. I thought something along the lines:
I create the thresholds directly on the ColorScaleFormatting with getColorScaleFormatting().createThreshold(). So what if setNumControlPoints() actually resets all the thresholds which have been previously created?
And that was the point where I simply moved rule.getColorScaleFormatting().setNumControlPoints(3); in before the creation of all the XSSFConditionalFormattingThreshold and there it was, my code working just fine.
Having a look at the setNumControlPoints method we can see this:
public void setNumControlPoints(int num) {
while (num < _scale.sizeOfCfvoArray()) {
_scale.removeCfvo(_scale.sizeOfCfvoArray()-1);
_scale.removeColor(_scale.sizeOfColorArray()-1);
}
while (num > _scale.sizeOfCfvoArray()) {
_scale.addNewCfvo();
_scale.addNewColor();
}
}
This clearly suggests that some things might get removed when calling this method, though I couldn't quite get what the initial size of _scale.sizeOfCfvoArray() is (I'd assume 0). And because of that I couldn't quite see how stuff gets removed, because I created 3 thresholds (_scale.sizeOfCfvoArray() should be 3) and then I call setNumControlPoints(3), so we would have num == _scale.sizeOfCfvoArray() and I couldn't find anything for what happens in that case (looks like complete removal of everything though).
To conclude, setNumControlPoints(int num) should always be called as first thing after creating the rule and before creating any thresholds.
If anyone can point out why everything gets reset if num == _scale.sizeOfCfvoArray(), feel free to comment or edit.
Like i sad , i am working on Euler problem 12 https://projecteuler.net/problem=12 , i believe that this program will give the correct answer but is too slow , i tried to wait it out but even after 9min it still cant finish it. How can i modify it to run faster ?
package highlydivisibletriangularnumber_ep12;
public class HighlyDivisibleTriangularNumber_EP12 {
public static void findTriangular(int triangularNum){
triangularValue = triangularNum * (triangularNum + 1)/2;
}
static long triangularValue = 0l;
public static void main(String[] args) {
long n = 1l;
int counter = 0;
int i = 1;
while(true){
findTriangular(i);
while(n<=triangularValue){
if(triangularValue%n==0){
counter++;
}
n++;
}
if(counter>500){
break;
}else{
counter = 0;
}
n=1;
i++;
}
System.out.println(triangularValue);
}
}
Just two simple tricks:
When x%n == 0, then also x%m == 0 with m = x/n. This way you need to consider only n <= Math.ceil(sqrt(x)), which is a huge speed up. With each divisor smaller than the square root, you get another one for free. Beware of the case of equality. The speed gain is huge.
As your x is a product of two numbers i and i+1, you can generate all its divisors as product of the divisors of i and i+1. What makes it more complicated is the fact that in general, the same product can be created using different factors. Can it happen here? Do you need to generate products or can you just count them? Again, the speed gain is huge.
You could use prime factorization, but I'm sure, these tricks alone are sufficient.
It appears to me that your algorithm is a bit too brute-force, and due to this, will consume an enormous amount of cpu time regardless of how you might rearrange it.
What is needed is an algorithm that implements a formula that calculates at least part of the solution, instead of brute-forcing the whole thing.
If you get stuck, you can use your favorite search engine to find a number of solutions, with varying degrees of efficiency.
During my app development one performance question came to my mind:
I have a lot of lines of data that can looks like that:
!ANG:-0.03,0.14,55.31
!ANG:-0.03,-0.14,305.31
!ANG:-234.03,-0.14,55.31
in general: !ANG:float,float,float
Between those lines there are also "damaged" lines - they don't start with ! or are too short/have extra signs and so on.
To detect lines that are damaged at the begining I simply use
if(myString.charAt(0) != '!')//wrong string
What I can do to detect lines that are damaged at the end? It is very important to mention that I need not only to check if the line is correct but also get those 3 float numbers to use it later.
I've found three options for this:
use regexp
split twice (first ":" and second ",") and count elements
use Scanner class
I am not sure which one of this (or maybe there are other) methods will be the best from the performance point of view. Can you please give me some advice?
EDIT:
After some comments I see that it is worth to write how damage lines an look:
NG:-0.03,0.14,55.31
.14,55.31
!ANG:-0.03,0.14,
!A,-0.02,-0.14,554,-0.12,55
It is quite difficult to talk about number of lines because I am getting them from readings from other device so I get packets of around 20 lines at a time with a frequency of 50Hz.
What I've found out so far is the big drawback of using scanner - for each line I need to create new object and after some time my device is starting to get short on resources.
Benchmark them, then you will know.
The likely fastest way is to write your own tiny state machine to match your format and find the float boundaries. Theoretically a regex will have the same performance, but it's likely to have additional overhead.
As an intermediate solution I'd do something like that :
private static class LineObject {
private float f1, f2, f3;
}
private LineObject parseLine(String line) {
LineObject obj = null;
if (line.startsWith("!ANG:")) {
int i = line.indexOf(',', 5);
if (i != -1) {
int j = line.indexOf(',', i+1);
if (j != -1) {
try {
obj = new LineObject();
obj.f1 = Float.parseFloat(line.substring(5, i));
obj.f2 = Float.parseFloat(line.substring(i+1, j));
obj.f3 = Float.parseFloat(line.substring(++j));
} catch (NumberFormatException e) {
return null;
}
}
}
}
return obj;
}
After you can copy/paste only usefull jdk code of startsWith, indexOf and parseFloat in your own state machine...
Okay, I'm making this new game in Java. This might be a simple question, but can anyone please help me with this?
So, if the "Guy" collides with the platforms, he can't move right (obviously).
This is what I got:
if(Guy.x + Guy.width == (platform2.x ^ platform3.x)) {} else{
goRight();
}
The "^" is supposed to be "or".
I have a void called goRight();
so it would be like "if Guy's x plus Guy's width is the same as platform2 or platform3's x then go right. I don't want to have to do this:
if(Guy.x + Guy.width == platform2.x || Guy.x + Guy.width == platform3.x)) {} else{
goRight();
}
And plus, I have like 20 more platforms so it would be easier the first way if it's possible.
And I have to make the left collision detection too.
You will have to repeat the conditions.
One (better) solution would be to create a collection with your x variables and using the .contains() method on it. That would make your code a lot more readable.
Alternatively, put all your platforms in a collection, loop over it and check each value's x variable.
You need some more advanced structures to store information about your platforms. Consider having a Set of the x-coordinates of your platforms and performing the operation 'contains`
for example:
Set<Integer> xcoords = new HashSet<Integer>();
xcoords.add(platform2.x);
xcoords.add(platform3.x);
if (xcoords.contains(Guy.x + Guy.width)){
} else {
goRight();
}
If Platform is a class that has an x value, then I'd suggest putting put all of your platforms into a collection of some kind and iterating over it. Inside a loop, do something like
for(Platform p: platforms){
if(Guy.getX() + Guy.getWidth() == p.getX()){
//whatever
}else{
goRight()
}
}
That's the way the language is designed... So it is useless to fight against it.
All you can do is use auxiliary variables to shorten the expressions. But you will always have to right something like if(a == b || a == c).
Its not really an animation, but I want it so i have a flashing underscore next to my text. I want this to simulate that more text can be entered..
e.g. one second its '_' and the other second its gone..
Thanks :D
ps I tried an idea where i had a while(flashing) loop and in there i made a string equal '_' and then made it equal '' but that didnt work..
while(flashing) {
s = "_";
s = "";
}
Thanks for the help in advance!
EDIT:::
This is how i am displaying the string in the game:
drawCenteredString(fontRenderer, "Missile Command Center" + s, width / 2, 40, 0xffffff);
Like #Vulcan said, you actually can't do this with a while loop. You have to 'redraw' the centeredString every second or so, once with an underscore and next time without the underscore
You didn't tell us what kind of graphic libraries you are using.
If you want to do something like a flashing underscore there are two ways, one can be very bad, the second can be better.
The first one is something just like (pseudocoded):
while(flashing){
textView.setText(textView.getText()+"_"); // I am assuming that you are using a text view, take this as pseudocode, you can do to whatever you want.
sleep(500); //that is half a second
textView.setText(textView.getText().substr(0,textView.getText().length()-1));
sleep(500);
}
The second is better.
I assume you are using something like OpenGL to draw the graphics (as minecraft do, if I remember well).
private long timePassed = 0;
public void draw(long delta){
timePassed += delta;
String t = textView.getText();
if(timepassed > blinkingSpeed){
timepassed = 0;
if("_".equals(t.substr(t.length()-1,t.length()))){
//The last char is the underscore, i remove it.
textView.setText(t.substr(0,t.length()-1));
}else{
//The last char isn't an underscore. I add it.
textView.setText(t + "_");
}
}
delta is a difference between the last time we done a loop and the actual time.
so when calling draw method you should have something like this
//metod where draw is called
delta = Sys.getTimer() - lastTimerGotten;
lastTimerGotten = Sys.getTimer();
draw(delta);
//etc etc
Obviously each frame rendering you should call the draw(long delta) method.
I hope you understand what I am trying to explain you.
There is no way to make what you first wrote work.