//=============================================================================================== //STREAM.EXE //Copyright (c), Firelight Technologies Pty, Ltd, 1999-2004. // //This example takes a command line parameter, a wav/mp2/mp3/ogg etc file, and uses the streamer //system to play it back. //=============================================================================================== /** * I've ported the C++ Fmod sample to use it with NativeFmod * * @author J�r�me JOUVIE (Jouvieje) * * WANT TO CONTACT ME ? * @author J�r�me JOUVIE (Jouvieje) * @site http://jerome.jouvie.free.fr/ * @mail jerome.jouvie@gmail.com */ package org.jouvieje.Fmod.Extras; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import javax.swing.JOptionPane; import org.jouvieje.Fmod.Fmod; import org.jouvieje.Fmod.Init; import org.jouvieje.Fmod.Callbacks.FSOUND_CLOSECALLBACK; import org.jouvieje.Fmod.Callbacks.FSOUND_OPENCALLBACK; import org.jouvieje.Fmod.Callbacks.FSOUND_READCALLBACK; import org.jouvieje.Fmod.Callbacks.FSOUND_SEEKCALLBACK; import org.jouvieje.Fmod.Callbacks.FSOUND_STREAMCALLBACK; import org.jouvieje.Fmod.Callbacks.FSOUND_TELLCALLBACK; 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_OUTPUTTYPES; import org.jouvieje.Fmod.Exceptions.InitException; import org.jouvieje.Fmod.Misc.BufferUtils; import org.jouvieje.Fmod.Misc.ObjectPointer; import org.jouvieje.Fmod.Misc.Pointer; import org.jouvieje.Fmod.Structures.FSOUND_SAMPLE; import org.jouvieje.Fmod.Structures.FSOUND_STREAM; import java.awt.Dimension; import java.awt.GridBagLayout; import java.awt.HeadlessException; import javax.swing.JTextArea; import java.awt.GridBagConstraints; import javax.swing.JApplet; import javax.swing.JTextField; import javax.swing.JButton; import javax.swing.JLabel; import java.awt.Color; import javax.swing.JScrollPane; public class StreamApplet extends JApplet implements Runnable, FSOUND_OUTPUTTYPES, FSOUND_INIT_FLAGS, FSOUND_MODES, FSOUND_MISC_VALUES, VERSIONS { private static final long serialVersionUID = 1L; private FSOUND_STREAM stream; private FSOUND_SAMPLE sptr; private ByteBuffer streamingBuffer; private int channel = -1; private boolean streamEnded = false; private char key; private boolean init = false; private boolean deinit = false; public void init() { /*====================== NativeFmod Init & Version checking ============================*/ try { JOptionPane.showMessageDialog(null, "Before loading libraries"); Init.DEBUG = true; Init.loadLibraries(); JOptionPane.showMessageDialog(null, "After loading libraries"); } catch(InitException e) { printExit("NativeFmod error! " + e.getMessage()); return; } try { /* * 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 + ")"); return; } /*====================== Checking FMOD Version checking ============================*/ JOptionPane.showMessageDialog(null, "FMOD Library version..."); if(Fmod.FSOUND_GetVersion() < FMOD_VERSION) { printExit("Error : You are using the wrong DLL version! You should be using FMOD " + FMOD_VERSION); return; } JOptionPane.showMessageDialog(null, "FMOD Library version: OK"); init = true; /*======================= Initialize the GUI ===========================*/ initialize(); } catch(HeadlessException e) { e.printStackTrace(); printExit("Unexpected exception: " + e.getMessage()); return; } } public void start() { Thread thread = new Thread(this); thread.start(); } public void run() { if(!init) return; String[] args = new String[1]; args[0] = "/Media/jbtennis.wav"; print("-------------------------------------------------------------\n"); print("FMOD Streamer example. [mp2 mp3 wav ogg wma asf]\n"); print("Copyright (c) Firelight Technologies Pty, Ltd, 1999-2004.\n"); print("-------------------------------------------------------------\n"); print("Output: No Sound-\n"); print("-------------------------------------------------------------\n"); // Set custom file callbacks? This doesnt have to be done, its just here as an example. Fmod.FSOUND_File_SetCallbacks(myopen, myclose, myread, myseek, mytell); Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_NOSOUND); // ========================================================================================== // INITIALIZE // ========================================================================================== if(!Fmod.FSOUND_Init(44100, 32, 0)) { String message = "FMOD Error: " + Fmod.FMOD_ErrorString(Fmod.FSOUND_GetError()); Fmod.FSOUND_Close(); printExit(message); return; } Fmod.FSOUND_Stream_SetBufferSize(1000); // ========================================================================================== // OPEN STREAM (use if(true) for streaming from memory) // ========================================================================================== if(false) { int length = 0; byte[] datas = null; RandomAccessFile file = null; try { file = new RandomAccessFile(args[0], "rw"); //rw = read and write } catch(FileNotFoundException e) { String message = "Error: File Not Found"; Fmod.FSOUND_Close(); printExit(message); return; } try { length = (int)file.length(); datas = new byte[length]; file.read(datas); file.close(); } catch(Exception e) { printExit("Error reading the file"); return; } streamingBuffer = BufferUtils.newByteBuffer(datas.length); streamingBuffer.put(datas); streamingBuffer.rewind(); //Go to the beginning of the buffer //The memory pointer MUST remain valid while streaming ! (keeps buffer referenced somewhere) stream = Fmod.FSOUND_Stream_Open(streamingBuffer, FSOUND_NORMAL | FSOUND_MPEGACCURATE | FSOUND_LOADMEMORY, 0, length); if(stream == null) { printExit("Can't creates the stream !!!"); return; } } else { if(args[0].startsWith("http:")) { print("Connecting to " + args[0] + ", please wait (this may take some time)....\n"); } stream = Fmod.FSOUND_Stream_Open(args[0], FSOUND_NORMAL | FSOUND_MPEGACCURATE, 0, 0); if(stream == null) { String message = "FMOD Error: " + Fmod.FMOD_ErrorString(Fmod.FSOUND_GetError()); Fmod.FSOUND_Close(); printExit(message); return; } } // ========================================================================================== // SET AN END OF STREAM CALLBACK AND RIFF SYNCH POINTS CALLBACK // ========================================================================================== Fmod.FSOUND_Stream_SetEndCallback(stream, endcallback, null); Fmod.FSOUND_Stream_SetSyncCallback(stream, endcallback, null); print("=========================================================================\n"); print("Press SPACE to pause/unpause\n"); print("Press f to fast forward 2 seconds\n"); print("Press e to quit\n"); print("=========================================================================\n"); sptr = Fmod.FSOUND_Stream_GetSample(stream); if(sptr != null) { int[] freq = new int[1]; Fmod.FSOUND_Sample_GetDefaults(sptr, freq, null, null, null); print("Name : " + Fmod.FSOUND_Sample_GetName(sptr) + "\n"); print("Frequency : " + freq[0] + "\n"); print("\n"); } do { if(channel < 0) { // ========================================================================================== // PLAY STREAM // ========================================================================================== channel = Fmod.FSOUND_Stream_PlayEx(FSOUND_FREE, stream, null, true); Fmod.FSOUND_SetPaused(channel, false); } if(key == ' ') Fmod.FSOUND_SetPaused(channel, !Fmod.FSOUND_GetPaused(channel)); else if(key == 'f') Fmod.FSOUND_Stream_SetTime(stream, Fmod.FSOUND_Stream_GetTime(stream) + 2000); key = 0; printr("pos " + Fmod.FSOUND_Stream_GetPosition(stream) + "/" + Fmod.FSOUND_Stream_GetLength(stream) + " time " + (Fmod.FSOUND_Stream_GetTime(stream) / 1000 / 60) + ":" + (Fmod.FSOUND_Stream_GetTime(stream) / 1000 % 60) + "/" + (Fmod.FSOUND_Stream_GetLengthMs(stream) / 1000 / 60) + ":" + (Fmod.FSOUND_Stream_GetLengthMs(stream) / 1000 % 60) + " cpu " + Fmod.FSOUND_GetCPUUsage() + "%"); try { Thread.sleep(100); } catch(Exception e) {} } while(!streamEnded && key != 'e' && key != 'E'); stop(); } public void stop() { if(!init || deinit) { return; } deinit = true; print("\n"); print("Shutdown stream\n"); if(stream != null && !stream.isNull()) { Fmod.FSOUND_Stream_Close(stream); } print("Shutdown FMOD\n"); Fmod.FSOUND_Close(); } //====================== File System ============================ private ByteBuffer loadFileIntoMemory(String name) throws IOException, FileNotFoundException { InputStream is = getClass().getResourceAsStream(name); BufferedInputStream bis = new BufferedInputStream(is); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] bytes = new byte[4 * 1024]; int read; while((read = bis.read(bytes, 0, bytes.length)) != -1) { baos.write(bytes, 0, read); } bis.close(); ByteBuffer buffer = BufferUtils.newByteBuffer(baos.size()); buffer.put(baos.toByteArray()); buffer.rewind(); return buffer; } /* * File callbacks */ private FSOUND_OPENCALLBACK myopen = new FSOUND_OPENCALLBACK(){ public Pointer FSOUND_OPENCALLBACK(String name) { try { ByteBuffer file = loadFileIntoMemory(name); return ObjectPointer.create(file); } catch(Exception e) { e.printStackTrace(); print("Failed to open the file " + name + " !!!\n"); return null; } } }; private FSOUND_CLOSECALLBACK myclose = new FSOUND_CLOSECALLBACK(){ public void FSOUND_CLOSECALLBACK(Pointer handle) { ObjectPointer objectPointer = ObjectPointer.createView(handle); objectPointer.release(); } }; private FSOUND_READCALLBACK myread = new FSOUND_READCALLBACK(){ public int FSOUND_READCALLBACK(ByteBuffer buffer, int size, Pointer handle) { ByteBuffer file = (ByteBuffer)ObjectPointer.createView(handle).getObject(); ByteBuffer fileChunk = file.duplicate(); fileChunk.limit(fileChunk.position() + size); if(fileChunk.remaining() != size) { printExit("Unexpected error while reading file !"); return 0; } buffer.put(fileChunk); file.position(file.position() + size); return size; } }; //Values taken from stdio.h public final int SEEK_CUR = 1; //Seek from the current position of file pointer public final int SEEK_END = 2; //Seek from the end of file public final int SEEK_SET = 0; //Seek from the beginning of file private FSOUND_SEEKCALLBACK myseek = new FSOUND_SEEKCALLBACK(){ public int FSOUND_SEEKCALLBACK(Pointer handle, int pos, byte mode) { ByteBuffer file = (ByteBuffer)ObjectPointer.createView(handle).getObject(); int position = 0; switch(mode) { case SEEK_CUR: position = file.position() + pos; break; case SEEK_END: position = file.capacity() + pos; break; case SEEK_SET: position = pos; break; } if(position < 0 || position > file.capacity()) { print("Error seeking file, invalid position (" + position + ")\n"); return -1; } file.position(position); return 0; } }; private FSOUND_TELLCALLBACK mytell = new FSOUND_TELLCALLBACK(){ public int FSOUND_TELLCALLBACK(Pointer handle) { ByteBuffer buffer = (ByteBuffer)ObjectPointer.createView(handle).getObject(); return buffer.position(); } }; /* * [DESCRIPTION] * End of stream user callback, initialized with FSOUND_Stream_SetEndCallback or * FSOUND_Stream_SetSynchCallback * * [PARAMETERS] * 'stream' A pointer to the stream that ended. * 'buff' This is null for end of stream callbacks, or a string for synch callbacks. * 'len' This is reserved and is always 0 for end and synch callbacks. ignore. * 'param' This is the value passed to FSOUND_Stream_SetEndCallback or * FSOUND_Stream_SetSynchCallback as a user data value. * [RETURN_VALUE] * true or false, the value is ignored. */ private FSOUND_STREAMCALLBACK endcallback = new FSOUND_STREAMCALLBACK(){ public boolean FSOUND_STREAMCALLBACK(FSOUND_STREAM stream, ByteBuffer buff, int len, Pointer userdata) { // end of stream callback doesnt have a 'buff' value, if it doesnt it could be a synch point. print("\n"); if(buff != null) { //To prints the String value stored in the ByteBuffer, you can use : String synchpoint = BufferUtils.toString(buff); print("SYNCHPOINT : " + synchpoint + "\n"); } else { print("STREAM ENDED!!\n"); streamEnded = true; } return true; } }; //====================== GUI Interaction ============================ private void print(String message) { getOutputTA().append(message); } private void printr(String message) { String text = getOutputTA().getText(); int index = text.lastIndexOf("\n"); if(index >= 0) text = text.substring(0, index + 1); getOutputTA().setText(text + message); } private void printExit(String message) { JOptionPane.showMessageDialog(this, message); stop(); // System.exit(0); } //====================== GUI ============================ private JTextArea outputTA = null; private JTextField inputTF = null; private JButton inputSendB = null; private JScrollPane outputSP = null; private void initialize() { GridBagConstraints gridBagConstraints3 = new GridBagConstraints(); gridBagConstraints3.gridx = 0; gridBagConstraints3.gridy = 1; GridBagConstraints gridBagConstraints2 = new GridBagConstraints(); gridBagConstraints2.gridx = 2; gridBagConstraints2.gridy = 1; GridBagConstraints gridBagConstraints1 = new GridBagConstraints(); gridBagConstraints1.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints1.gridy = 1; gridBagConstraints1.weightx = 1.0; gridBagConstraints1.gridx = 1; GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.gridy = 0; gridBagConstraints.weighty = 1.0; gridBagConstraints.gridwidth = 3; gridBagConstraints.gridx = 0; this.setLayout(new GridBagLayout()); this.setSize(new Dimension(353, 193)); this.add(getOutputSP(), gridBagConstraints); this.add(getInputTF(), gridBagConstraints1); this.add(getInputSendB(), gridBagConstraints2); this.add(new JLabel("Input"), gridBagConstraints3); } private JScrollPane getOutputSP() { if(outputSP == null) { outputSP = new JScrollPane(); outputSP.setViewportView(getOutputTA()); } return outputSP; } private JTextArea getOutputTA() { if(outputTA == null) { outputTA = new JTextArea(); outputTA.setEditable(false); outputTA.setBackground(new Color(220, 220, 220)); } return outputTA; } private JTextField getInputTF() { if(inputTF == null) { inputTF = new JTextField(); } return inputTF; } private JButton getInputSendB() { if(inputSendB == null) { inputSendB = new JButton(); inputSendB.setText("Validate"); inputSendB.addActionListener(new java.awt.event.ActionListener(){ public void actionPerformed(java.awt.event.ActionEvent e) { if(inputTF.getText().length() > 0) key = inputTF.getText().charAt(0); else key = 0; } }); } return inputSendB; } } // @jve:decl-index=0:visual-constraint="10,10"