Rhythm
The program in the previous article is able to replay simple melody. However, the interpretor doesn't have ways to define rhythm. That means every musical note has the same duration. In order to play simple song, we need to define duration modifier in our simple interpretor. Let's define the modifiers as follows :
"-"
The duration of the previous note is doubled"/"
The duration of the previous note is reduced by half"."
The duration of the previous note is extended by a factor of 1.5
With the above modifier, the song "Jingle Bells" can be represented by the following string :
String m="eee-eee-egc.d/e---fff.f/feee/e/edded-g-eee-eee-egc.d/e---fff.f/feee/e/ggfdc---";
Jingle Bells
The following is a program that play the song "Jingle Bells". It is a modification of the program in the previous post./****************************************************************************** * File : Jingle.java * Author : http://java.macteki.com/ * Description : * Play "Jingle Bells" * Tested with : JDK 1.6 ******************************************************************************/ class Jingle { static void beep(double frequency, int duration) throws Exception { int nChannel = 1; // number of channel : 1 or 2 // samples per second float sampleRate = 16000; // valid:8000,11025,16000,22050,44100 int nBit = 16; // 8 bit or 16 bit sample int bytesPerSample = nChannel*nBit/8; double durationInSecond = (double) duration/1000.0; int bufferSize = (int) (nChannel*sampleRate*durationInSecond*bytesPerSample); byte[] audioData = new byte[bufferSize]; // "type cast" to ShortBuffer java.nio.ByteBuffer byteBuffer = java.nio.ByteBuffer.wrap(audioData); java.nio.ShortBuffer shortBuffer = byteBuffer.asShortBuffer(); int sampleLength = audioData.length/bytesPerSample; // generate the sine wave double volume = 8192; // 0-32767 double PI = Math.PI; for(int i = 0; i < sampleLength; i++){ double time = i/sampleRate; double freq = frequency; double angle = 2*PI*freq*time; double sinValue = Math.sin(angle); double fade=1; int decay=sampleLength*1/3; // start fade out at 2/3 of the total time if (i>=sampleLength-1-decay) fade=(double)(sampleLength-1-i)/decay; short amplitude = (short) (volume*fade*sinValue); for (int c=0;c<nChannel;c++) { shortBuffer.put(amplitude); } }//end generating sound wave sample boolean isSigned=true; boolean isBigEndian=true; // Define audio format javax.sound.sampled.AudioFormat audioFormat = new javax.sound.sampled.AudioFormat(sampleRate, nBit, nChannel, isSigned,isBigEndian); javax.sound.sampled.DataLine.Info dataLineInfo = new javax.sound.sampled.DataLine.Info( javax.sound.sampled.SourceDataLine.class, audioFormat); // get the SourceDataLine object javax.sound.sampled.SourceDataLine sourceDataLine = (javax.sound.sampled.SourceDataLine) javax.sound.sampled.AudioSystem.getLine(dataLineInfo); sourceDataLine.open(audioFormat); sourceDataLine.start(); // actually play the sound sourceDataLine.write(audioData,0,audioData.length); // "flush", wait until the sound is completed sourceDataLine.drain(); } public static void main(String[] args) throws Exception { java.util.Hashtable<String,Integer> frequencyTable= new java.util.Hashtable<String,Integer>(); frequencyTable.put("c",262); // frequency of middle C frequencyTable.put("d",294); frequencyTable.put("e",330); frequencyTable.put("f",349); frequencyTable.put("g",392); frequencyTable.put("a",440); frequencyTable.put("b",494); frequencyTable.put("C",523); frequencyTable.put("D",587); frequencyTable.put("E",659); String song="eee-eee-egc.d/e---fff.f/feee/e/edded-g-eee-eee-egc.d/e---fff.f/feee/e/ggfdc---"; int full=250; int half=full/2; for (int i=0;i<song.length();i++) { int duration=full; String s=song.substring(i,i+1); // get pitch Integer freq = frequencyTable.get(s); // get duration modifier int j=i+1; while (j<song.length()) { String s1=song.substring(j,j+1); if (s1.equals("/")) { duration-=half; } else if (s1.equals(".")) { duration+=half; } else if (s1.equals("-")) duration+=full; else break; j++; } if (freq!=null) beep(freq, duration); } } }
this tutorial and website are great, it's really helping me get my head around java.
ReplyDeleteThanks for reading.
DeleteGreat blog man, thank you for sharing the knowledge!
ReplyDeleteThanks for reading. Be sure to share this site with a friend.
Delete