/* RECORD.EXE Copyright (c), Firelight Technologies Pty, Ltd, 2000-2004. This example shows how to record data to a static sample, or record dynamically, and have a dsp unit processing the result. The reverb below is taken from /samples/fmod/fmod.c */ /** * I've ported the C++ FMOD example to use it with NativeFmod * * @author J�r�me JOUVIE (Jouvieje) * * WANT TO CONTACT ME ? * E-mail : * jerome.jouvie@gmail.com * My web sites : * http://jerome.jouvie.free.fr/ */ package org.jouvieje.Fmod.Examples; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import javax.swing.JPanel; import org.jouvieje.Fmod.Fmod; import org.jouvieje.Fmod.Init; import org.jouvieje.Fmod.Callbacks.FSOUND_DSPCALLBACK; import org.jouvieje.Fmod.Defines.FSOUND_DSP_PRIORITIES; import org.jouvieje.Fmod.Defines.FSOUND_INIT_FLAGS; import org.jouvieje.Fmod.Defines.FSOUND_MISC_VALUES; import org.jouvieje.Fmod.Defines.FSOUND_MODES; import org.jouvieje.Fmod.Defines.VERSIONS; import org.jouvieje.Fmod.Enumerations.FSOUND_FX_MODES; import org.jouvieje.Fmod.Enumerations.FSOUND_MIXERTYPES; import org.jouvieje.Fmod.Enumerations.FSOUND_OUTPUTTYPES; import org.jouvieje.Fmod.Examples.Util.ConsoleGUI; import org.jouvieje.Fmod.Examples.Util.FmodExampleFrame; import org.jouvieje.Fmod.Exceptions.InitException; import org.jouvieje.Fmod.FileFormat.WavFormat.DataChunk; import org.jouvieje.Fmod.FileFormat.WavFormat.FmtChunk; import org.jouvieje.Fmod.FileFormat.WavFormat.RiffChunk; import org.jouvieje.Fmod.FileFormat.WavFormat.WavHeader; import org.jouvieje.Fmod.Misc.BufferUtils; import org.jouvieje.Fmod.Misc.FileWriterUtils; import org.jouvieje.Fmod.Misc.ObjectPointer; import org.jouvieje.Fmod.Misc.Pointer; import org.jouvieje.Fmod.Misc.PointerUtils; import org.jouvieje.Fmod.Structures.FSOUND_SAMPLE; import org.jouvieje.libloader.LibLoader; public class Record extends ConsoleGUI implements FSOUND_INIT_FLAGS, FSOUND_DSP_PRIORITIES, FSOUND_MODES, FSOUND_MISC_VALUES, FSOUND_OUTPUTTYPES, FSOUND_MIXERTYPES, FSOUND_FX_MODES, VERSIONS { private static final long serialVersionUID = 1L; public static void main(String[] args) { new FmodExampleFrame(new Record()); } public Record() { super(); initFmod(); initialize(); } public JPanel getPanel() { return this; } public String getTitle() { return "FMOD Record example."; } private final boolean ENABLEREVERB = true; private final int RECORDRATE = 44100; private final int RECORDLEN = (RECORDRATE * 5); /* 5 seconds at RECORDRATE khz */ private final int OUTPUTRATE = 44100; private int REVERB_NUMTAPS = 7; private boolean init = false; private boolean deinit = false; private FSOUND_SAMPLE samp1 = null; private int channel = 0; /* * Reverb stuff */ private REVERBTAP[] DSP_ReverbTap = new REVERBTAP[REVERB_NUMTAPS]; /* * [DESCRIPTION] * Callback to mix in one reverb tap. It copies the buffer into its own history buffer also. * * [PARAMETERS] * 'originalbuffer' Pointer to the original mixbuffer, not any buffers passed down * through the dsp chain. They are in newbuffer. * 'newbuffer' Pointer to buffer passed from previous DSP unit. * 'length' Length in SAMPLES of buffer being passed. * 'userdata' User parameter. In this case it is a pointer to DSP_LowPassBuffer. * * [RETURN_VALUE] * a pointer to the buffer that was passed in, with a tap mixed into it. */ private FSOUND_DSPCALLBACK DSP_ReverbCallback = new FSOUND_DSPCALLBACK(){ public ByteBuffer FSOUND_DSPCALLBACK(ByteBuffer originalbuffer, ByteBuffer newBuffer, int length, Pointer userdata) { REVERBTAP tap = (REVERBTAP)ObjectPointer.createView(userdata).getObject(); int mixerType = Fmod.FSOUND_GetMixer(); int bytesPerOutputSample; if(mixerType == Fmod.FSOUND_MIXER_QUALITY_MMXP5 || mixerType == Fmod.FSOUND_MIXER_QUALITY_MMXP6) bytesPerOutputSample = 4; // 16bit stereo else bytesPerOutputSample = 8; // 32bit stereo /* * reverb history buffer is a ringbuffer. If the length makes the copy wrap, then split the copy * into end part, and start part.. */ if(tap.historyOffset + length > tap.historyLen) { int taillen = tap.historyLen - tap.historyOffset; int startlen = length - taillen; // mix a scaled version of history buffer into output tap.historyBuff.position(tap.historyOffset << 2); Fmod.FSOUND_DSP_MixBuffers(newBuffer, tap.historyBuff, taillen, 44100, tap.volume, tap.pan, FSOUND_STEREO | FSOUND_16BITS); tap.historyBuff.rewind(); newBuffer.position(taillen * bytesPerOutputSample); Fmod.FSOUND_DSP_MixBuffers(newBuffer, tap.historyBuff, startlen, 44100, tap.volume, tap.pan, FSOUND_STEREO | FSOUND_16BITS); newBuffer.rewind(); // now copy input into reverb/history buffer tap.historyBuff.position(tap.historyOffset << 2); for(int i = 0; i <= taillen * 2 - 1; i++) { int val; if(mixerType == Fmod.FSOUND_MIXER_QUALITY_FPU) { val = (int)newBuffer.getFloat(); } else if(mixerType == Fmod.FSOUND_MIXER_QUALITY_MMXP5 || mixerType == Fmod.FSOUND_MIXER_QUALITY_MMXP6) { val = (int)newBuffer.getShort(); } else { val = newBuffer.getInt(); } val = (val > Short.MAX_VALUE ? Short.MAX_VALUE : val < Short.MIN_VALUE ? Short.MIN_VALUE : val); tap.historyBuff.putShort((short)val); } tap.historyBuff.rewind(); newBuffer.rewind(); newBuffer.position(taillen * bytesPerOutputSample); for(int i = 0; i <= startlen * 2 - 1; i++) { int val; if(mixerType == Fmod.FSOUND_MIXER_QUALITY_FPU) { val = (int)newBuffer.getFloat(); } else if(mixerType == Fmod.FSOUND_MIXER_QUALITY_MMXP5 || mixerType == Fmod.FSOUND_MIXER_QUALITY_MMXP6) { val = (int)newBuffer.getShort(); } else { val = newBuffer.getInt(); } val = (val > Short.MAX_VALUE ? Short.MAX_VALUE : val < Short.MIN_VALUE ? Short.MIN_VALUE : val); tap.historyBuff.putShort((short)val); } } // no wrapping reverb buffer, just write dest else { // mix a scaled version of history buffer into output tap.historyBuff.position((tap.historyOffset << 2)); Fmod.FSOUND_DSP_MixBuffers(newBuffer, tap.historyBuff, length, 44100, tap.volume, tap.pan, FSOUND_STEREO | FSOUND_16BITS); // now copy input into reverb/history buffer for(int i = 0; i <= length * 2 - 1; i++) { int val; if(mixerType == Fmod.FSOUND_MIXER_QUALITY_FPU) { val = (int)newBuffer.getFloat(); } else if(mixerType == Fmod.FSOUND_MIXER_QUALITY_MMXP5 || mixerType == Fmod.FSOUND_MIXER_QUALITY_MMXP6) { val = (int)newBuffer.getShort(); } else { val = newBuffer.getInt(); } val = (val > Short.MAX_VALUE ? Short.MAX_VALUE : val < Short.MIN_VALUE ? Short.MIN_VALUE : val); tap.historyBuff.putShort((short)val); } } tap.historyBuff.rewind(); newBuffer.rewind(); tap.historyOffset += length; if(tap.historyOffset >= tap.historyLen) { tap.historyOffset -= tap.historyLen; } // reverb history has been mixed into new buffer, so return it. return newBuffer; } }; /* * REVERB SETUP */ private void SetupReverb() { /* something to fiddle with. */ int[] delay = new int[]{131, 149, 173, 211, 281, 401, 457}; /* prime numbers make it sound cool! */ int[] volume = new int[]{120, 100, 95, 90, 80, 60, 50}; int[] pan = new int[]{100, 128, 128, 152, 128, 100, 152}; for(int i = 0; i <= REVERB_NUMTAPS - 1; i++) { DSP_ReverbTap[i] = new REVERBTAP(); DSP_ReverbTap[i].delayMs = delay[i]; DSP_ReverbTap[i].volume = volume[i]; DSP_ReverbTap[i].pan = pan[i]; DSP_ReverbTap[i].historyOffset = 0; DSP_ReverbTap[i].historyLen = (DSP_ReverbTap[i].delayMs * 44100 / 1000); if(DSP_ReverbTap[i].historyLen < Fmod.FSOUND_DSP_GetBufferLength()) { DSP_ReverbTap[i].historyLen = Fmod.FSOUND_DSP_GetBufferLength(); /* just in case our calc is not the same. */ } DSP_ReverbTap[i].historyBuff = BufferUtils.newByteBuffer(4 * DSP_ReverbTap[i].historyLen); /* * 4 is for 16bit stereo (mmx only) */ DSP_ReverbTap[i].workArea = null; ObjectPointer userdata = ObjectPointer.create(DSP_ReverbTap[i]); DSP_ReverbTap[i].unit = Fmod.FSOUND_DSP_Create(DSP_ReverbCallback, FSOUND_DSP_DEFAULTPRIORITY_USER + 20 + 2 * i, userdata); Fmod.FSOUND_DSP_SetActive(DSP_ReverbTap[i].unit, true); } } private void closeReverb() { for(int i = 0; i <= REVERB_NUMTAPS - 1; i++) { if(DSP_ReverbTap[i].unit != null && !DSP_ReverbTap[i].unit.isNull()) { Fmod.FSOUND_DSP_Free(DSP_ReverbTap[i].unit); DSP_ReverbTap[i].unit = null; DSP_ReverbTap[i].historyBuff = null; DSP_ReverbTap[i].workArea = null; } } } /* * [DESCRIPTION] * Writes out the contents of a record buffer to a file. */ private void saveToWav(FSOUND_SAMPLE sample) { if(sample == null) return; long mode = Fmod.FSOUND_Sample_GetMode(sample); short bits = ((mode & FSOUND_16BITS) != 0) ? (short)16 : (short)8; short channels = ((mode & FSOUND_STEREO) != 0) ? (short)2 : (short)1; int lenbytes = (Fmod.FSOUND_Sample_GetLength(sample) * channels * bits / 8); int[] vRate = new int[1]; Fmod.FSOUND_Sample_GetDefaults(sample, vRate, null, null, null); int rate = vRate[0]; /* * WAV Structures */ WavHeader wavHeader = new WavHeader( new RiffChunk(new byte[]{'R', 'I', 'F', 'F'}, FmtChunk.SIZEOF_FMT_CHUNK + RiffChunk.SIZEOF_RIFF_CHUNK + lenbytes), new byte[]{'W', 'A', 'V', 'E'}); FmtChunk fmtChunk = new FmtChunk( new RiffChunk(new byte[]{'f', 'm', 't', ' '}, FmtChunk.SIZEOF_FMT_CHUNK - RiffChunk.SIZEOF_RIFF_CHUNK), (short)1, channels, rate, rate * channels * bits / 8, (short)(1 * channels * bits / 8), bits); DataChunk dataChunk = new DataChunk(new RiffChunk(new byte[]{'d', 'a', 't', 'a'}, lenbytes)); try { RandomAccessFile file = new RandomAccessFile("record.wav", "rw"); /* * Write out the WAV header. */ WavHeader.writeWavHeader(file, wavHeader); FmtChunk.writeFmtChunk(file, fmtChunk); DataChunk.writeDataChunk(file, dataChunk); /* * Lock the sample to get acces to the data */ Pointer ptr1 = new Pointer(); Pointer ptr2 = new Pointer(); int[] len1 = new int[1]; int[] len2 = new int[1]; Fmod.FSOUND_Sample_Lock(sample, 0, lenbytes, ptr1, ptr2, len1, len2); //Write datas ByteBuffer datas = PointerUtils.toBuffer(ptr1, len1[0]); FileWriterUtils.writeByteBuffer(file, datas); /* * Unlock the sample */ Fmod.FSOUND_Sample_Unlock(sample, ptr1, ptr2, len1[0], len2[0]); //Close the file file.close(); } catch(FileNotFoundException e) { print("Fails to write in the file ! " + e.getMessage() + "\n"); } catch(IOException e) { print("Fails to write in the file ! " + e.getMessage() + "\n"); } } private long oldrecordpos = 0, oldplaypos = 0; private float smoothedvu = 0; /* * [DESCRIPTION] * Main example function * * [PARAMETERS] * 'argc' Number of arguments passed on the command line * 'argv' Pointer to an array of arguments. */ public void initFmod() { /* * NativeFmod Init */ try { Init.loadLibraries(); } catch(InitException e) { printExit("NativeFmod error! " + e.getMessage() + "\n"); return; } /* * Checking NativeFmodEx version */ if(NATIVEFMOD_LIBRARY_VERSION != NATIVEFMOD_JAR_VERSION) { printExit("Error! NativeFmod library version (" + NATIVEFMOD_LIBRARY_VERSION + ") is different to jar version (" + NATIVEFMOD_JAR_VERSION + ")\n"); return; } /*==================================================*/ /* * Checking Fmod version */ if(Fmod.FSOUND_GetVersion() < FMOD_VERSION) { printExit("Error : You are using the wrong DLL version! You should be using FMOD " + FMOD_VERSION + "\n"); return; } init = true; } public void run() { if(!init) return; /* * SELECT OUTPUT METHOD */ print("---------------------------------------------------------\n"); print("Output Type\n"); print("---------------------------------------------------------\n"); switch (LibLoader.getPlatform()) { case LibLoader.PLATFORM_WINDOWS: print("1 - Direct Sound\n"); print("2 - Windows Multimedia Waveout\n"); print("3 - NoSound\n"); break; case LibLoader.PLATFORM_LINUX: print("1 - OSS - Open Sound System\n"); print("2 - ESD - Elightment Sound Daemon\n"); print("3 - ALSA 0.9 - Advanced Linux Sound Architecture\n"); break; case LibLoader.PLATFORM_MACOSX: print("1 - Mac SoundManager\n"); break; } print("---------------------------------------------------------\n"); /* print driver names */ print("Press a corresponding number\n"); int output = -1; while(output < 1 || output > 4) { try { output = Integer.parseInt("" + getKey()); } catch(NumberFormatException e) { output = -1; } Thread.yield(); } switch (LibLoader.getPlatform()) { case LibLoader.PLATFORM_WINDOWS: switch(output) { case 1: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); break; case 2: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_WINMM); break; case 3: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_ASIO); break; } break; case LibLoader.PLATFORM_LINUX: switch(output) { case 1: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_OSS); break; case 2: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_ESD); break; case 3: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_ALSA); break; } break; case LibLoader.PLATFORM_MACOSX: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_MAC); break; default: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_NOSOUND); break; } /* * SELECT OUTPUT DRIVER */ /* The following list are the drivers for the output method selected above. */ print("---------------------------------------------------------\n"); //Print output name printOutput(); print(" Driver list\n"); print("---------------------------------------------------------\n"); for(int i = 0; i < Fmod.FSOUND_GetNumDrivers(); i++) { print(i + " - " + Fmod.FSOUND_GetDriverName(i) + "\n"); /* print driver names */ } print("---------------------------------------------------------\n"); /* print driver names */ print("Press a corresponding number\n"); int driver = -1; while(driver < 0 || driver > Fmod.FSOUND_GetNumDrivers() - 1) { try { driver = Integer.parseInt("" + getKey()); } catch(NumberFormatException e) { driver = -1; } Thread.yield(); } Fmod.FSOUND_SetDriver(driver); /* Select sound card (0 = default) */ /* * SELECT MIXER */ Fmod.FSOUND_SetMixer(FSOUND_MIXER_QUALITY_AUTODETECT); /* * INITIALIZE */ if(!Fmod.FSOUND_Init(OUTPUTRATE, 64, FSOUND_INIT_ACCURATEVULEVELS)) { printExit(Fmod.FMOD_ErrorString(Fmod.FSOUND_GetError())); return; } /* * SELECT INPUT DRIVER (can be done before or after init) */ /* The following list are the drivers for the output method selected above. */ print("---------------------------------------------------------\n"); printOutput(); print(" Recording device driver list\n"); print("---------------------------------------------------------\n"); for(int i = 0; i < Fmod.FSOUND_Record_GetNumDrivers(); i++) { print(i + " - " + Fmod.FSOUND_Record_GetDriverName(i) + "\n"); /* print driver names */ } print("---------------------------------------------------------\n"); /* print driver names */ print("Press a corresponding number\n"); int record = -1; while(record < 0 || record > Fmod.FSOUND_Record_GetNumDrivers() - 1) { try { record = Integer.parseInt("" + getKey()); } catch(NumberFormatException e) { record = -1; } Thread.yield(); } if(!Fmod.FSOUND_Record_SetDriver(record)) /* Select input sound card (0 = default) */ { String error = Fmod.FMOD_ErrorString(Fmod.FSOUND_GetError()); print("Shutdown FMOD\n"); Fmod.FSOUND_Close(); printExit(error); return; } /* * DISPLAY HELP */ print("FSOUND Output Method : "); output = Fmod.FSOUND_GetOutput(); if(output == FSOUND_OUTPUT_NOSOUND) print("FSOUND_OUTPUT_NOSOUND\n"); else if(output == FSOUND_OUTPUT_WINMM) print("FSOUND_OUTPUT_WINMM\n"); else if(output == FSOUND_OUTPUT_DSOUND) print("FSOUND_OUTPUT_DSOUND\n"); else if(output == FSOUND_OUTPUT_ASIO) print("FSOUND_OUTPUT_ASIO\n"); else if(output == FSOUND_OUTPUT_OSS) print("FSOUND_OUTPUT_OSS\n"); else if(output == FSOUND_OUTPUT_ESD) print("FSOUND_OUTPUT_ESD\n"); else if(output == FSOUND_OUTPUT_ALSA) print("FSOUND_OUTPUT_ALSA\n"); else if(output == FSOUND_OUTPUT_MAC) print("FSOUND_OUTPUT_MAC\n"); else print("\n"); print("FSOUND Mixer : "); int mixer = Fmod.FSOUND_GetMixer(); if(mixer == FSOUND_MIXER_QUALITY_FPU) print("FSOUND_MIXER_QUALITY_FPU\n"); else if(mixer == FSOUND_MIXER_QUALITY_MMXP5) print("FSOUND_MIXER_QUALITY_MMXP5\n"); else if(mixer == FSOUND_MIXER_QUALITY_MMXP6) print("FSOUND_MIXER_QUALITY_MMXP6\n"); else if(mixer == FSOUND_MIXER_MONO) print("FSOUND_MIXER_MONO\n"); else if(mixer == FSOUND_MIXER_QUALITY_MONO) print("FSOUND_MIXER_QUALITY_MONO\n"); else print("\n"); print("FSOUND Driver : " + Fmod.FSOUND_GetDriverName(Fmod.FSOUND_GetDriver()) + "\n"); print("FSOUND Record Driver : " + Fmod.FSOUND_Record_GetDriverName(Fmod.FSOUND_Record_GetDriver()) + "\n"); /* * RECORD INTO A STATIC SAMPLE */ /* * Create a sample to record into */ if(Fmod.FSOUND_GetOutput() == FSOUND_OUTPUT_OSS) { samp1 = Fmod.FSOUND_Sample_Alloc(FSOUND_UNMANAGED, RECORDLEN, FSOUND_MONO | FSOUND_8BITS | FSOUND_UNSIGNED, RECORDRATE, 255, 128, 255); } else { samp1 = Fmod.FSOUND_Sample_Alloc(FSOUND_UNMANAGED, RECORDLEN, FSOUND_STEREO | FSOUND_16BITS, RECORDRATE, 255, 128, 255); } print("\n"); print("=========================================================================\n"); print("Press ENTER to start recording 5 seconds worth of data\n"); print("=========================================================================\n"); readInput(""); if(!Fmod.FSOUND_Record_StartSample(samp1, false)) {/* it will record into this sample for 5 seconds then stop */ String error = Fmod.FMOD_ErrorString(Fmod.FSOUND_GetError()); print("Shutdown FMOD\n"); Fmod.FSOUND_Close(); printExit(error); return; } do { printr("Recording position = " + Fmod.FSOUND_Record_GetPosition()); try { Thread.sleep(500); } catch(InterruptedException e) {} } while(Fmod.FSOUND_Record_GetPosition() < RECORDLEN); Fmod.FSOUND_Record_Stop(); /* it already stopped anyway */ print("\n"); print("=========================================================================\n"); print("Press ENTER to play back recorded data\n"); print("=========================================================================\n"); readInput(""); channel = Fmod.FSOUND_PlaySound(FSOUND_FREE, samp1); print("Playing back sound...\n"); do { printr("Playback position = " + Fmod.FSOUND_GetCurrentPosition(channel)); try { Thread.sleep(500); } catch(InterruptedException e) {} } while(Fmod.FSOUND_IsPlaying(channel)); if(Fmod.FSOUND_GetOutput() == FSOUND_OUTPUT_OSS) { Fmod.FSOUND_Sample_Free(samp1); print("Shutdown FMOD\n"); Fmod.FSOUND_Close(); printExit(""); return; } /* * SAVED TO */ saveToWav(samp1); print("\nSaved to record.wav!\n\n"); /* * REALTIME FULL DUPLEX RECORD / PLAYBACK! */ print("=========================================================================\n"); print("Press ENTER to do some full duplex realtime recording!\n"); print("(with reverb for mmx users)\n"); print("=========================================================================\n"); readInput(""); Fmod.FSOUND_Sample_SetMode(samp1, FSOUND_LOOP_NORMAL); /* make it a looping sample */ if(!Fmod.FSOUND_Record_StartSample(samp1, true)) {/* start recording and make it loop also */ String error = Fmod.FMOD_ErrorString(Fmod.FSOUND_GetError()); print("Shutdown FMOD\n"); Fmod.FSOUND_Close(); printExit(error); return; } /* * Increase this value if the sound sounds corrupted or the time between recording * and hearing the result is longer than it should be.. */ final int RECORD_DELAY_MS = 25; final float RECORD_DELAY_SAMPLES = (RECORDRATE * RECORD_DELAY_MS / 1000); /* * Let the record cursor move forward a little bit first before we try to play it * (the position jumps in blocks, so any non 0 value will mean 1 block has been recorded) */ while(Fmod.FSOUND_Record_GetPosition() != 0) { try { Thread.sleep(10); } catch(InterruptedException e) {} } if(ENABLEREVERB) SetupReverb(); channel = Fmod.FSOUND_PlaySound(FSOUND_FREE, samp1); /* play the sound */ int originalfreq = Fmod.FSOUND_GetFrequency(channel); // println("initial delay = "+(Fmod.FSOUND_GetCurrentPosition(channel)-Fmod.FSOUND_Record_GetPosition())); resetInput(); do { long playpos = Fmod.FSOUND_GetCurrentPosition(channel); int recordpos = Fmod.FSOUND_Record_GetPosition(); /* * NOTE : As the recording and playback frequencies arent guarranteed to be exactly in * sync, we have to adjust the playback frequency to keep the 2 cursors just enough * apart not to overlap. (and sound corrupted) * This code tries to keep it inside a reasonable size window just behind the record * cursor. ie [........|play window|<-delay->|<-Record cursor.............] */ /* * Dont do this code if either of the cursors just wrapped */ long diff = 0; if(playpos > oldplaypos && recordpos > oldrecordpos) { diff = playpos - recordpos; if(diff > -RECORD_DELAY_SAMPLES) Fmod.FSOUND_SetFrequency(channel, originalfreq - 1000); /* slow it down */ else if(diff < -(RECORD_DELAY_SAMPLES * 2)) Fmod.FSOUND_SetFrequency(channel, originalfreq + 1000); /* speed it up */ else Fmod.FSOUND_SetFrequency(channel, originalfreq); } oldplaypos = playpos; oldrecordpos = recordpos; /* * Print some info and a VU meter (vu is smoothed) */ float[] l = new float[1]; float[] r = new float[1]; float vuval; Fmod.FSOUND_GetCurrentLevels(channel, l, r); vuval = (l[0] + r[0]) * 0.5f; vuval *= 18.0f; final float VUSPEED = 0.2f; if(vuval > smoothedvu) smoothedvu = vuval; smoothedvu -= VUSPEED; if(smoothedvu < 0) smoothedvu = 0; String vu = ""; for(int i = 0; i < (int)(smoothedvu); i++) { vu += '='; } printr("Play=" + playpos + " Rec=" + recordpos + " (gap=" + diff + ", freqchange=" + (Fmod.FSOUND_GetFrequency(channel) - originalfreq) + " hz) VU:" + vu); try { Thread.sleep(10); } catch(InterruptedException e) {} } while(!keyHit() && !deinit); stop(); } public void stop() { if(!init || deinit) { return; } deinit = true; Fmod.FSOUND_StopSound(channel); Fmod.FSOUND_Record_Stop(); if(ENABLEREVERB) { closeReverb(); } /* * CLEANUP AND SHUTDOWN */ if(samp1 != null && !samp1.isNull()) Fmod.FSOUND_Sample_Free(samp1); print("Shutdown FMOD\n"); Fmod.FSOUND_Close(); } private void printOutput() { int output = Fmod.FSOUND_GetOutput(); if(output == FSOUND_OUTPUT_NOSOUND) print("NoSound"); else if(output == FSOUND_OUTPUT_WINMM) print("Windows Multimedia Waveout"); else if(output == FSOUND_OUTPUT_DSOUND) print("Direct Sound"); else if(output == FSOUND_OUTPUT_ASIO) print("ASIO"); else if(output == FSOUND_OUTPUT_OSS) print("Open Sound System"); else if(output == FSOUND_OUTPUT_ESD) print("Enlightment Sound Daemon"); else if(output == FSOUND_OUTPUT_ALSA) print("Advanced Linux Sound Architecture"); else if(output == FSOUND_OUTPUT_MAC) print("Mac SoundManager"); } }