Sound Demo 3

Aus ProgrammingWiki

Wiki-Quelltext dieser Seite.

<language>Java</language>
<code id="4b58377106264" hidden>
javax.sound.sampled.AudioFormat audioFormat;
javax.sound.sampled.AudioInputStream audioInputStream;
javax.sound.sampled.SourceDataLine sourceDataLine;
float sampleRate = 16000.0F;
int sampleSizeInBits = 16;
int channels = 1;
boolean signed = true;
boolean bigEndian = true;
audioData = new byte[16000*16];

void fillBuffer(double startat,double freq) {
 java.nio.ByteBuffer byteBuffer;
 java.nio.ShortBuffer shortBuffer;
 int byteLength;
 byteBuffer = java.nio.ByteBuffer.wrap(audioData);
 shortBuffer = byteBuffer.asShortBuffer();
 byteLength = audioData.length;

 channels = 1;//Java allows 1 or 2
 int bytesPerSamp = 2;
 int sampLength = byteLength / bytesPerSamp;
 for (int cnt = 0; cnt < sampLength; cnt++)
 {
  double time = cnt / sampleRate;
  double sinValue = playFunction(startat/2+time,freq);
  shortBuffer.put((short)(16000 * sinValue));
 }
}

void draw(int dauer, double start,double freq){ 
 dauer = dauer * 2;
 canvas.clear(); 
 double oldy = 100;
 canvas.setColor(200,200,200);
 canvas.line(0,100,600,100);
 canvas.setColor(0,0,0);
 for(int x=0; x< 600; x++) {   
   double newy = 100+100*playFunction(start/2+((double)dauer/2/600*x),freq);   
   if(start/2+(double)dauer/2/600*x == 0){
    canvas.setColor(200,200,200);
    canvas.line(x,0,x,200);
    canvas.setColor(0,0,0);
   }
   canvas.line((x-1),(int)(oldy),x,(int)(newy));  
   oldy = newy; 
 }
}

void play(int dauer, double startat,double freq){
 dauer = dauer * 2;
 audioData = new byte[16000*dauer];
 try{
 fillBuffer(startat,freq);
 InputStream byteArrayInputStream =  new ByteArrayInputStream(audioData);
 audioFormat = new javax.sound.sampled.AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
 audioInputStream = new javax.sound.sampled.AudioInputStream(byteArrayInputStream, audioFormat,  
                        audioData.length / audioFormat.getFrameSize());
 javax.sound.sampled.DataLine.Info dataLineInfo = 
       new javax.sound.sampled.DataLine.Info(javax.sound.sampled.SourceDataLine.class, audioFormat);
 sourceDataLine = (javax.sound.sampled.SourceDataLine)javax.sound.sampled.AudioSystem.getLine(dataLineInfo);
 sourceDataLine.open(audioFormat);
 sourceDataLine.start();
 playBuffer = new byte[16384];
 int cnt;
 while ((cnt = audioInputStream.read(playBuffer, 0,playBuffer.length))!= -1)
  if (cnt > 0) sourceDataLine.write(playBuffer, 0, cnt);
 sourceDataLine.drain();
 sourceDataLine.stop();
 sourceDataLine.close();
 }
 catch (Exception e){e.printStackTrace();System.exit(0);}
}
</code>
Mit diesem Beispiel kann man Funktionen hörbar machen. In diesem Beispiel werden 3 Sinuskurven zu einem Ton zusammengefügt. Gleichzeitig wird mit <tt>gain</tt> ein Abklingen des Tones simuliert. 

<eval id="4b58377106a33">
// erzeugt eine Art Glockenschlag
double playFunction(double x, double freq){
      double gain = 1.0-Math.log(x+1)/1.8;
      if(gain < 0) gain = 0;
      double sinValue =
        (Math.sin(2*Math.PI*freq*x) +
         Math.sin(2*Math.PI*(freq/1.8)*x) +
         Math.sin(2*Math.PI*(freq/1.5)*x))/3.0;
      return (sinValue)*gain;
}

draw(5,0,500.0); // 5 Sekunden diese Funktion spielen und mit x=0 beginnen
play(5,0,500.0); // Frequenz von 500 Herz
</run>

<canvas></canvas>


<code id="4b595bb5960fe" hidden>
void fillToneBuffer(byte[] a, double startat,double freq) {
 java.nio.ByteBuffer byteBuffer;
 java.nio.ShortBuffer shortBuffer;
 int byteLength;
 byteBuffer = java.nio.ByteBuffer.wrap(a);
 shortBuffer = byteBuffer.asShortBuffer();
 byteLength = a.length;

 channels = 1;//Java allows 1 or 2
 int bytesPerSamp = 2;
 int sampLength = byteLength / bytesPerSamp;
 for (int cnt = 0; cnt < sampLength; cnt++)
 {
  double time = cnt / sampleRate;
  double sinValue = ToneFunction(startat/2+time,freq);
  shortBuffer.put((short)(16000 * sinValue));
 }
}
Vector tones = new Vector();
void fillTones() {
  tones = new Vector();
  for(int i=0; i < 8; i++){
    tempBuffer = new byte[16000*1]; // 0.5 sekunden
    double f = 0;
    if(i == 0) f = 264.0;
    if(i == 1) f = 297.0;
    if(i == 2) f = 330.0;
    if(i == 3) f = 352.0;
    if(i == 4) f = 396.0;
    if(i == 5) f = 440.0;
    if(i == 6) f = 495.0;
    if(i == 7) f = 528.0;
    fillToneBuffer(tempBuffer,0,f);
    tones.add(tempBuffer);
  }
}
void playTone(int t) {
 try{
 audioData = (byte[]) tones.get(t);
 InputStream byteArrayInputStream =  new ByteArrayInputStream(audioData);
 audioFormat = new javax.sound.sampled.AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
 audioInputStream = new javax.sound.sampled.AudioInputStream(byteArrayInputStream, audioFormat,  
                        audioData.length / audioFormat.getFrameSize());
 javax.sound.sampled.DataLine.Info dataLineInfo = 
       new javax.sound.sampled.DataLine.Info(javax.sound.sampled.SourceDataLine.class, audioFormat);
 sourceDataLine = (javax.sound.sampled.SourceDataLine)javax.sound.sampled.AudioSystem.getLine(dataLineInfo);
 sourceDataLine.open(audioFormat);
 sourceDataLine.start();
 playBuffer = new byte[16384];
 int cnt;
 while ((cnt = audioInputStream.read(playBuffer, 0,playBuffer.length))!= -1)
  if (cnt > 0) sourceDataLine.write(playBuffer, 0, cnt);
 sourceDataLine.drain();
 sourceDataLine.stop();
 sourceDataLine.close();
 }
 catch (Exception e){e.printStackTrace();System.exit(0);}
}
void playTones(String s) {
   s = s.toLowerCase();
   for(int i=0; i < s.length(); i++){
    if(s.charAt(i) == 'c') playTone(0);
    if(s.charAt(i) == 'd') playTone(1);
    if(s.charAt(i) == 'e') playTone(2);
    if(s.charAt(i) == 'f') playTone(3);
    if(s.charAt(i) == 'g') playTone(4);
    if(s.charAt(i) == 'a') playTone(5);
    if(s.charAt(i) == 'h') playTone(6);
   }
}
</code>
In diesem Beispiel werden zunächst die Grundtöne C,D,E,F,G,A und H in einem Vector durch die Funktion <tt>fillTones()</tt> vor berechnet. Anschließend wird eine Tonfolge ausgegeben. Sie können diese Zeichenkette und die <tt>ToneFunction</tt> beliebig anpassen.
<eval id="4b595bb5968ce">
double ToneFunction(double x, double freq){
      double gain = 1.0-Math.log(x+1)/0.6;
      if(gain < 0) gain = 0;
      double sinValue =
        (Math.sin(2*Math.PI*freq*x) +
         Math.sin(2*Math.PI*(freq/1.8)*x) +
         Math.sin(2*Math.PI*(freq/1.5)*x))/3.0;
      return (sinValue)*gain;
}
fillTones();
playTones("E E F G G F E D C C D E E D D"); // spielt eine Tonfolge ab.
</run>