I'm making a program that plays a sine wave varying in pitch and I'm dealing with something that i've never seen before: the program should play a sine wave from 220 hz to 0 hz, and I can see the frequency going from 220 to 0, but what I hear is a sine wave that goes from 220 to 0 and then back to 220.
I have no idea how this piece of code can do that
http://pastebin.com/HS36k7XJ (had to post it here because of screwed up layout)
(where t is the time in seconds and f the current frequency (which is calculated by a simple linear interpolation, which behaves properly))
You scale f linearly down to zero. This means that the expression t * Math.PI * 2 will be scaled back to zero as well. The value you pass to sin() goes from 0 initially (because t=0) to some positive value (because t>0 and f>0), back to 0 (because f=0).
Let's look at the values of t * Math.PI * 2 * f over time and the frequencies:
At t=0, the value is 0 and will increase with speed 220
At t=0.5, the value is 345 and will stop increasing
At t=1, the value is 0 again and will decrease with speed -220
It's reversing it's direction because t * Math.PI * 2 is multiplied by f, and f is getting smaller. This means the whole expression will become smaller as t approaches 1.
Try this code instead:
double ct = 0;
for (;;) {
if(t>=1) break;
//System.out.println(t+" "+e.getValueAt(t));
for (int i = 0; i < buff.length; i++) {
double f=lerp(fa,fb,t);
buff[i] = (short) (Short.MAX_VALUE * 0.5 * Math.sin(Math.PI * 2 * ct));
toSoundCard[2 * i] = (byte) buff[i];
toSoundCard[2 * i + 1] = (byte) (buff[i] >> 8); //(i know i could avoid doing this)
t += 1.0 / 44100.0;
ct += f / 44100.0;
}
speaker.write(toSoundCard, 0, toSoundCard.length);
}
Related
I am trying to get Processing to draw a sine wave. However, it appears like a badly sampled version of a sine wave on the output. Do I need to replace the shape with a series of lines, or is there another solution?
I've tried casting the variable to a float, and changing c++ to c += 1.
noFill();
stroke(255);
beginShape();
translate(0, 100);
for (int c = 0; c <= width; c += 1)
{
vertex(c, (float) 100 * sin(c / 50));
}
endShape();
I expect that it traverses the window pixel-by-pixel, creating a smooth shape.
What I actually get is what appears to be sampled, as shown here.
Quantized sine wave
The expression
c / 50
is an integral division. The result is an integral value. If 0 <= c < 50, then the result is 0, if 50 <= c < 100 then the result 1.
To do a floating point division, with a floating point result, on of the 2 values has to be floating point (e.g. c / 50.0).
Change the expression to solve the issue:
vertex(c, 100.0 * sin((float)c / 50.0));
I am trying to calculate sine of an angle without using the Math.sin(). I got stuck in it's equation as I keep getting the wrong results
note I have a method that changes the angle from degrees to radians
public static double sin(double x, int precision) {
//this method is simply the sine function
double answer = 1, power = 1;
int n = 2,factorial = 1;
while (n<=precision) {
power = (power * x * x *-1) +1 ;
factorial = (factorial * (n +1))* (n-1);
answer = answer + ((power/factorial ));
n = n + 2;
}
return answer;
}
It looks like you're attempting to calculate the sine of angle given in radians using the Maclaurin series, a special case of Taylor series.
sin(x) = x - x^3/3! + x^5/5! - x^7/7! + ...
Your initial answer is 1 when it should be x. Your initial power is 1 when it should be x also.
double answer = x, power = x;
For some reason you're adding one to the power part of the result when you shouldn't be.
power = (power * x * x * -1);
You'll also need to fix your factorial calculation. Multiply by n + 1 and n, not n + 1 and n - 1.
factorial = (factorial * (n + 1)) * (n);
With these fixes, testing:
for (double angle = 0; angle <= Math.PI; angle += Math.PI / 4)
{
System.out.println("sin(" + angle + ") = " + sin(angle, 10));
}
The results are pretty good considering the limitations of precision for floating point arithmetic.
sin(0.0) = 0.0
sin(0.7853981633974483) = 0.7071067811796194
sin(1.5707963267948966) = 0.999999943741051
sin(2.356194490192345) = 0.7070959900908971
sin(3.141592653589793) = -4.4516023820965686E-4
Note that this will get more inaccurate as the values of x get larger, not just because of the inaccuracy to represent pi, but also because of the floating point calculations for adding and subtracting large values.
I have two angles given to me; a starting one and an ending one.
I'm also in a loop with a specified numbers of loops.
I'm trying to split an angle up so at each loop iteration I create something at that angle.
Using 3 particles as an example
Here is the code (within in the loop, degrees are 90 to 180)
for (int i = 0; i < numberOfParticles(3); i++)
{
float percentage = 1f / numberOfParticles;
percentage *= index;
float angle = startingAngle + ((endingAngle - startingAngle) * percentage);
}
My problem is this produces : (instead of 90 (0), 135 (0.5), 180 (1))
Log: 90.0 | percentage: 0.0
Log: 120.0 | percentage: 0.33333334
Log: 149.99998 | percentage: 0.6666667
How would I get this to work with any number (including 7?)
You've got an off-by-one error. If you have 3 particles, you're going to start at 0% and then add 50% 2 times, not 3.
float percentage = 1f / (numberOfParticles - 1);
Make sure you also handle the edge case where numberOfParticles is 1. You don't want to divide by zero.
I have a number that is being increased by an increment on each step. Let's assume that start number is 0 and increment is 100.
On step #5 and later I want to start decreasing the base increment (100). The increment should be decreased smoothly and at step #10 it equals 0.
Here is a graph that basically explains what am I trying to do (y - increment, x - step).
Code representation:
// x - step
// y - increment
var value = 0;
for(var x = 0; x < 10; x++) {
var y = 100;
if(x > 5) {
// y = ???
}
value += y;
}
So the question is how to represent this? It would be also great to have an option to modify the smoothness of this arc.
Thank you!
This will give you a perfect quarter cirle that starts at (5|100) and ends at (10|0).
if (x > 5) {
y = 100 * Math.sqrt( 1 - Math.pow(((x - 5) / 5), 2) );
}
http://fooplot.com/plot/2i8hy2twl4
Explanation (optional)
Warning! May contain mathematics!
Let's start with a simpler case, a quarter circle with a radius of 1 and its center is (0|0). We know that x² + y² = r²(Pythagorean theorem). x and r are known, so we can calculate y this way: y = sqrt(r² - x²). Since our radius is always 1 and 1² is equal to 1, we can break it down to this:
y = sqrt(1 - x²)
The value of y ranges from 0 to 1. We want it to range from 0 to 100 though. To achieve this, we simply multiply the right side by 100.
y = 100 * sqrt(1 - x²)
^^^^^^
To shift the entire thing 5 to the right, we need to subtract 5 from x.
y = 100 * sqrt(1 - (x - 5)²)
^^^^^
Also, we want to stretch it to the right, so that our quarter circle ranges from x = 5 to x = 10 and not to x = 6, so wie divide (x - 5) by 5.
y = 100 * sqrt(1 - ((x - 5) / 5)^2)
^^^^
Everything to do now is to replace sqrt by Math.sqrt and ^2 by Math.pow to make it valid Javascript code.
y = 100 * Math.sqrt( 1 - Math.pow(((x - 5) / 5), 2) );
If that curve is a quarter circle, then the equation that you want is
y = 20 * Math.sqrt(x * (10 - x));
If it's not a quarter circle, then it's anyone's guess.
if (x<=5)
y = 100;
else if (x>=10)
y = 0;
else {
double radius = 100;
double offset = (x-5)*20;
y = Math.sqrt(raidus*radius - offset*offset);
}
http://fooplot.com/plot/offuyxbfzu
Can you please , explain to me (in words) what this code does?
thank you
My concerns are actually these two parts :
1)
double y_new = (double) (h * (128 - my_byte) / 256);
lines.add(new Line2D.Double(x, y_last, x, y_new));
y_last = y_new;
2) the for loop , I dont'understand...
what's 32768 ?
my_byte?
int numChannels = format.getChannels();
for (double x = 0; x < w && audioData != null; x++) {
int idx = (int) (frames_per_pixel * numChannels * x);
// se a 8 bit è immediato
if (format.getSampleSizeInBits() == 8) {
my_byte = (byte) audioData[idx];
} else {
my_byte = (byte) (128 * audioData[idx] / 32768);
Here's the code . It was taken from here :
http://www.koders.com/java/fid3508156A13C80A263E7CE65C4C9D6F5D8651AF5D.aspx?s=%22David+Anderson%22
(class Sampling Graph)
int frames_per_pixel = audioBytes.size() / format.getFrameSize() / w;
byte my_byte = 0;
double y_last = 0;
int numChannels = format.getChannels();
for (double x = 0; x < w && audioData != null; x++) {
// scegli quale byte visualizzare
int idx = (int) (frames_per_pixel * numChannels * x);
// se a 8 bit è immediato
if (format.getSampleSizeInBits() == 8) {
my_byte = (byte) audioData[idx];
} else {
my_byte = (byte) (128 * audioData[idx] / 32768);
}
double y_new = (double) (h * (128 - my_byte) / 256);
lines.add(new Line2D.Double(x, y_last, x, y_new));
y_last = y_new;
}
repaint();
Don't know if it helps, but
128 * someInt / 32768
is the same as
someInt << 7 >> 15
You should at the first place learn how a sound file is organized. But anyway..
double y_new = (double) (h * (128 - my_byte) / 256);
lines.add(new Line2D.Double(x, y_last, x, y_new));
y_last = y_new;
The Y positions of the lines that this example draws are representing the sample values of the sound file. As you may know one sample can be 8/16/32...bit. In this exaple they scale all bit values down to 8 (1 byte). The ne Y will have its center in the screen mid position (its a signed sound file). h is the screen hight-we want to scale it as if 127 is the screen top and -127 the screen lower pixel.
2) 32768 is the max value for a signed 16 bit integer. Thus, the max sample value for a 16 bit sound file. myByte: A sound file is saved as a byte stream. So evan if you use 16bit samples, you will have to create your integer (16bit, 32bin in Java) from the 2 bytes from the screen. In this example they work only with 8bit sample data, so if this example reads a 16bit sound file it will convert the sample values to 8 bit in this line:
my_byte = (byte) (128 * audioData[idx] / 32768);
So my byte holds the sample value of frame "idx".
double y_new = (double) (h * (128 - my_byte) / 256);
This line of code is part of a method to plot a sequence of bytes on a 'windows' (rectangle, coordinate system, as you like)
h := the height of the drawable area in pixel
my_byte := a byte [-128,127] (a 8 bit sample from an audio file?)
(128 - my_byte) converts the input [-128,127] to [256, 1]. Division by 256 transforms this range to [1, 1/256] and multiplying with the height h results in the expected mapping from [-128,127] --> [~0,h]
The following to lines are for drawing a line from the point representing the previous byte to the actual point. The actual point will then become the previous point for the next iteration.
my_byte = (byte) (128 * audioData[idx] / 32768);
This line of code is execute if the sample size is 16Bit. But we need an 8Bit value just for the plotting. An int in Java is 32 Bit, we have a 16 Bit sample, so the upper 16 Bit are 0, the lower 16 Bit store the audio sample value. The algorithm now shifts the value 7 positions to the left, then 15 to the right:
00000000 00000000 11111111 11111111
-> 00000000 01111111 11111111 10000000 // * 128, << 7
-> 00000000 00000000 00000000 11111111 // : 32768, >> 15
Honestly, i do not know why the author didn't just divide by 256 once, that should give the same result.
But anyway - the result is a byte that represents the eight most significant bits of the sample. Pretty inaccurate, by the way, because if you have a very quiete 16 bit recording you'll see nothing on the wave panel.