I’m creating an interactive ocilator,
by clicking on the bar
1-Create a sine wave in samples [] of “n_samples_wave” samples
2-then a thread reads sample by sample and passes it to audiodata [0]
3-sourcedataline writes audiodata samples sound card [0]
The problem is that pressing the bar takes a few milliseconds to hear the new frequency.
I want the frequency to change and be heard quickly as in http://www.szynalski.com/tone-generator/
float n_samples_wave=360;
float[] samples = new float[44100];//buffer of samples
import javax.sound.sampled.*;
//create thread for write samples in sound card
RunnableDemo R1 = new RunnableDemo( "Thread-1");
AudioFormat audioFormat;
SourceDataLine sourceDataLine;
byte audioData[] = new byte [44100];
float f=1;
HScrollbar hs1;
int sam=1;
void setup()
{
size(370, 360, P3D);
hs1 = new HScrollbar(0, height/2-8, width, 12, 16);
loadPixels();
playAudio();
R1.start();
updatePixels();
background(0);
}
void draw()
{
loadPixels();
//refresh screen
for(int yy=0 ; yy<180; yy++){
for(int xx=0 ; xx<width ;xx++){
setpixel(xx,yy,0);
}
}
// scrollbar to create wave
if (hs1.locked){ //if you press the scrollbar
f=hs1.getPos()/35;
n_samples_wave=44100/(122.5*f);//44100/360=122.5
//frequency 122.5 is formed by 360 samples
//frequency 1 is formed by 44100 samples
// create wave with "n_samples_wave" samples.
for(int i=0; i<n_samples_wave; i++){
samples[i]=20*sin(radians(i)*f);
}
}
// if (keyPressed && key=='z'){
//}
//show waveform
for(int i = 0; i < 359; i++)
{
// if (i==477){ stroke(255,0,0);}
stroke(255);
//if (i==1){thread("sine") ;};
line( i, 50 - samples[i], i+1, 50 - samples[i+1] );
}
//show buffer
line( 0, 50 , width, 50 );
stroke(255,255,0);
line(0,90,n_samples_wave,90);
line(n_samples_wave,50,n_samples_wave,90);
//line(0,240,width,240);
updatePixels();
// //n_samples_wave=44100/(122.5*1) freq 122.5=360 samples
hs1.update();
hs1.display();
fill(255);
}//end draw
private AudioFormat getAudioFormat(){
float samplerate = 44100.0F;
//8000,11025,16000,22050,44100
int sampleSizeInBits =8;
//8,16
int channels = 1;
//1,2
boolean signed = true;
//true,false
boolean bigEndian = true;
//true,false
return new AudioFormat(
samplerate,
sampleSizeInBits,
channels,
signed,
bigEndian);
}//end getAudioFormat
private void playAudio() {
try{
AudioFormat audioFormat = getAudioFormat();
DataLine.Info dataLineInfo = new DataLine.Info( SourceDataLine.class, audioFormat);
sourceDataLine = (SourceDataLine)
AudioSystem.getLine(dataLineInfo);
sourceDataLine.open(audioFormat);
sourceDataLine.start();
} catch (LineUnavailableException ev) {
}//end catch
}//end playAudio
class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
// thread will be constantly receiving the values of samples []
// "n_samples_wave" sample samples will be read [] and "n_samples_wave" samples will be written to the sound card each while
while(true){
for(int i=0; i<n_samples_wave; i+=1){
if ((map(samples[i],0,20,0,100))<127 && (map(samples[i],0,20,0,100))>-127 ) {
audioData[0]=byte (map(samples[i],0,20,0,100));
}
// samples can only have values from -127 to 127
if ((map(samples[i],0,20,0,100))>127 ) { // if the current sample has a value greater than 127
audioData[0]=byte (127);
}
if ((map(samples[i],0,20,0,100))<-127 ) {
audioData[0]=byte (-127);
}
sourceDataLine.write( audioData, 0,1);
}
}
}//run()
public void start () {
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}//end class
void setpixel( int x, int y , color col)
{
pixels[x+width*y]=color(col);
}
int getpixel(PGraphics arr, int x, int y )
{
return int(arr.pixels[x+arr.width*y]);
}
int getpixel( int x, int y )
{
return int(pixels[x+width*y]);
}
int getpixel(PImage arr, int x, int y )
{
return int(arr.pixels[x+arr.width*y]);
}