package com.frinika.codeexamples;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import com.frinika.voiceserver.AudioContext;
import com.frinika.voiceserver.VoiceInterrupt;
import com.frinika.voiceserver.VoiceServer;
import com.frinika.voiceserver.voicetemplate.SynchronizedVoice;
import com.frinika.project.ProjectContainer;
import com.frinika.project.gui.ProjectFrame;
import com.frinika.sequencer.SongPositionListener;
/*
* Created on Mar 8, 2006
*
* Copyright (c) 2004-2006 Peter Johan Salomonsen (http://www.petersalomonsen.com)
*
* http://www.frinika.com
*
* This file is part of Frinika.
*
* Frinika is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Frinika is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Frinika; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* Simple example of audio playback within Frinika. This is just meant to be a guidance of how to implement audio
* playback. It's not intended that the audio playback voice should be constantly present, like it is in this example.
* This is only for testing purposes.
*
* Replace the audio clip file with a file of your own.
*
* A good test case, is an export of a project to wav, and play it along with the metronome (remember to have the same tempo).
*
* @author Peter Johan Salomonsen
*/
public class AudioPlayBackExample {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
// Create the audio context
final VoiceServer voiceServer = new AudioContext().getVoiceServer();
// Set up a synchronized voice
class AudioTestVoice extends SynchronizedVoice {
AudioInputStream ais;
boolean running = false;
byte[] byteBuffer = null;
public AudioTestVoice(VoiceServer voiceServer, int i) throws Exception {
super(voiceServer,i);
reopenStream();
}
/**
* Probably not the best way to reset the stream.
*/
void reopenStream() throws Exception
{
// Replace this with a clip of your own (NOTE: This example assumes a STEREO 16 bit wav)
//ais = AudioSystem.getAudioInputStream(new File("/home/peter/mystudio/20060618.wav"));
ais = AudioSystem.getAudioInputStream(new File("/home/pjl/samples/Sassy9.wav"));
}
/**
* Tell the voice whether to play or not (if the sequencer is running)
*/
public void setRunning(final boolean running)
{
// This has to be in a voiceinterrupt, so that it's changed according to the current latency
voiceServer.interruptTransmitter(this, new VoiceInterrupt() {
@Override
public void doInterrupt() {
AudioTestVoice.this.running = running;
}});
}
@Override
public void fillBufferSynchronized(int startBufferPos, int endBufferPos, float[] buffer) {
if(!running)
return;
// Correct byte buffer size
if(byteBuffer==null || byteBuffer.length!=buffer.length*2)
byteBuffer = new byte[buffer.length*2];
// Check for glitch
if(getMissedFrames()!=0)
{
// Glitch correction goes here
try
{
// Just reopen the stream (probably not a good solution), and skip to the correct framepos
reopenStream();
ais.skip(getFramePos()*4);
} catch(Exception e)
{
e.printStackTrace();
}
}
try {
// Read from the stream
ais.read(byteBuffer,startBufferPos*2,(endBufferPos-startBufferPos)*2);
} catch (IOException e) {
e.printStackTrace();
}
// Decode byte data and insert into voiceserver buffer
for(int n=startBufferPos;n<endBufferPos;n++)
buffer[n] += ((short)((0xff & byteBuffer[(n*2)+0]) + ((0xff & byteBuffer[(n*2)+1]) * 256)) / 32768f);
}
};
final AudioTestVoice voice = new AudioTestVoice(voiceServer, 0);
// Now add to the voiceServer
voiceServer.addTransmitter(voice);
// Create the project container
final ProjectContainer proj = new ProjectContainer();
// Sequencer synchronization goes here
proj.getSequencer().addSongPositionListener(new SongPositionListener() {
public void notifyTickPosition(long tick) {
voice.setRunning(proj.getSequencer().isRunning());
voice.setFramePos( (proj.getSequencer().getMicrosecondPosition() * voiceServer.getSampleRate()) / 1000000);
}
public boolean requiresNotificationOnEachTick() {
return false;
}});
// Show the project frame
new ProjectFrame(proj);
}
}