package rasmus;
import com.frinika.voiceserver.AudioContext;
import com.frinika.voiceserver.Voice;
import com.frinika.voiceserver.VoiceServer;
import java.io.File;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import javax.sound.midi.Instrument;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Receiver;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.Soundbank;
import javax.sound.midi.Synthesizer;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.Line;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.TargetDataLine;
public class SoundfontSynthTest {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
// 1. Find RasmusDSP Synthesizer
// -----------------------------
MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
MidiDevice.Info info = null;
for (int i = 0; i < infos.length; i++) {
if(infos[i].getName().equals("RasmusDSP Synthesizer"))
info = infos[i];
}
if(info == null) return; // RasmusDSP Synthesizer wasn't found!
// 2. Open RasmusDSP Synthesizer
// -----------------------------
MidiDevice mididevice = MidiSystem.getMidiDevice(info);
mididevice.open();
// 3. Get TargetLine from Synthesizer (if needed and supported)
// Must be done before calling "mididevice.getReceiver()"
// ------------------------------------------------------------
TargetDataLine dataline = null;
boolean pcm_float = false;
if(mididevice instanceof Mixer)
{
dataline = (TargetDataLine)((Mixer)mididevice).getLine( new Line.Info(TargetDataLine.class));
try
{
AudioFormat.Encoding PCM_FLOAT = new AudioFormat.Encoding("PCM_FLOAT");
AudioFormat format = new AudioFormat(PCM_FLOAT, 44100, 32, 2, 4*2, 4*2*44100, true);
dataline.open(format);
pcm_float = true;
}
catch(Exception e)
{
System.out.println("PCM_FLOAT not supported - " + e.toString());
AudioFormat format = new AudioFormat(44100, 16, 2, true, false);
dataline.open(format);
}
}
//
// 6. Read some data from the audio stream if dataline != null
// -----------------------------------------------------------
if(dataline!=null)
{
// Initialize the Frinika voiceServer
VoiceServer voiceServer = new AudioContext().getVoiceServer();
final TargetDataLine line = dataline;
// Add a voice representing the soundfont synth
if(pcm_float)
{
System.out.println("PCM_FLOAT Encoding used!");
voiceServer.addTransmitter(new Voice(){
byte[] streamBuffer = null;
FloatBuffer floatBuffer = null;
@Override
public void fillBuffer(int startBufferPos, int endBufferPos, float[] buffer) {
if(streamBuffer==null || streamBuffer.length!=buffer.length*4)
{
ByteBuffer bytebuffer = ByteBuffer.allocate(buffer.length*4);
streamBuffer = bytebuffer.array();
floatBuffer = bytebuffer.asFloatBuffer();
}
line.read(streamBuffer, 0, (endBufferPos-startBufferPos)*4);
floatBuffer.position(0);
floatBuffer.get(buffer, startBufferPos, endBufferPos - startBufferPos);
}});
}
else
voiceServer.addTransmitter(new Voice(){
byte[] streamBuffer = null;
//Frinika uses 32 bit float.. so a conversion is needed
@Override
public void fillBuffer(int startBufferPos, int endBufferPos, float[] buffer) {
if(streamBuffer==null || streamBuffer.length!=buffer.length*2)
streamBuffer = new byte[buffer.length*2];
// This is a bit clumsy - converting to byte for converting it back to float again - but temporarily
line.read(streamBuffer, startBufferPos*2, (endBufferPos-startBufferPos)*2);
// Convert to 32 bit float
for(int n=startBufferPos;n<endBufferPos;n++)
{
buffer[n] = (((short)((0xff & streamBuffer[n*2+0]) + ((0xff & streamBuffer[n*2+1]) * 256))) / 65536f);
}
}});
}
// 4. Load SoundBank into Synthesizer if supported
// -----------------------------------------------
Thread.sleep(1000);
if(mididevice instanceof Synthesizer)
{
Soundbank soundbank = MidiSystem.getSoundbank(new File("soundfonts/Club.SF2"));
((Synthesizer)mididevice).loadAllInstruments(soundbank);
}
// 5. Get MIDI Receiver from Synthesizer
// -------------------------------------
Receiver receiver = mididevice.getReceiver();
// Set the patch
ShortMessage shm = new ShortMessage();
Instrument instr = ((Synthesizer)mididevice).getAvailableInstruments()[0];
System.out.println(instr.getName());
shm.setMessage(ShortMessage.CONTROL_CHANGE, 9, 0, 1);
receiver.send(shm, -1);
shm.setMessage(ShortMessage.CONTROL_CHANGE, 9, 0x20,0);
receiver.send(shm, -1);
shm.setMessage(ShortMessage.PROGRAM_CHANGE ,9,instr.getPatch().getProgram(),0);
receiver.send(shm, -1);
boolean evenBeat = true;
/**
* Play the beat
*/
while(true)
{
System.out.println("Kick");
// Kick
shm = new ShortMessage();
shm.setMessage(ShortMessage.NOTE_ON,9,36,100);
receiver.send(shm, -1);
// Hat
shm = new ShortMessage();
shm.setMessage(ShortMessage.NOTE_ON,9,42,100);
receiver.send(shm, -1);
Thread.sleep(300);
// Open Hat
shm = new ShortMessage();
shm.setMessage(ShortMessage.NOTE_ON,9,46,100);
receiver.send(shm, -1);
Thread.sleep(300);
// Snare
shm = new ShortMessage();
shm.setMessage(ShortMessage.NOTE_ON,9,40,100);
receiver.send(shm, -1);
// Hat
shm = new ShortMessage();
shm.setMessage(ShortMessage.NOTE_ON,9,42,100);
receiver.send(shm, -1);
Thread.sleep(300);
// Open Hat
shm = new ShortMessage();
shm.setMessage(ShortMessage.NOTE_ON,9,46,100);
receiver.send(shm, -1);
Thread.sleep(150);
// On even beats put in a kick for variation
if(evenBeat)
{
// Kick
shm = new ShortMessage();
shm.setMessage(ShortMessage.NOTE_ON,9,36,70);
receiver.send(shm, -1);
Thread.sleep(150);
}else
{
Thread.sleep(150);
}
evenBeat = !evenBeat;
}
// 7. Free everythink after user
// -----------------------------
//if(dataline != null) dataline.close();
//mididevice.close();
}
}