Dynamic Audio / Sound Synthesis: DynamicAudioStream (code, working)

i couldnt find how to play dynamically synthesized sampled sound (creating the sound in a memory buffer) in JME…  so this code subclasses AudioInputStream into DynamicAudioStream.



is there a better way to do this?  if not, maybe something similar can be added to JME.



public class TestDynamicJMESound extends SimpleGame {

   private AudioSystem audio;

   class DynamicAudioStream extends AudioInputStream {

      private int samplesPerSecond = 44100;

      public DynamicAudioStream() throws IOException {
         
         //supply a dummy URL for the superclass
         super(DynamicAudioStream.class.getClassLoader().getResource("."), 10.0f);
         
      }
      
      @Override public int available() {
         return samplesPerSecond;
      }

      @Override public int getBitRate() {
         return getChannelCount() * getDepth()/8 * samplesPerSecond;
      }

      @Override public int getChannelCount() {
         return 1;
      }

      @Override public int getDepth() {
         return 16;
      }

      @Override public AudioInputStream makeNew() throws IOException {
         return this;
      }

      /** synthesizes the next audio buffer */
      @Override public int read(ByteBuffer b, int offset, int length)   throws IOException {
         //System.out.println("read: " + b+ " " + offset + " " + length);
         
         for (int i = offset; i < length; i++) {
            b.put(i, (byte)(Math.random() * 200));
         }
         return length;
      }
      
   }
   
   class DynamicAudioTrack extends AudioTrack {
      
      private StreamedAudioPlayer stream;

      public DynamicAudioTrack() {
         
         //supply dummy URL for superclass
         super(DynamicAudioStream.class.getClassLoader().getResource("."), true);
         
         try {
            this.stream = new OpenALStreamedAudioPlayer(new DynamicAudioStream(), this);
            stream.init();
         } catch (IOException e) {
            e.printStackTrace();
            return;
         }
         
         
         setPlayer(stream);

         setEnabled(true);
         
         setType(TrackType.HEADSPACE);
         setRelative(false);
         setTargetVolume(0.9F);

      }
      
      
   }
   
   public static void main(String[] args) {
      TestDynamicJMESound app = new TestDynamicJMESound();

      app.setDialogBehaviour(NEVER_SHOW_PROPS_DIALOG);
      app.start();
   }

   @Override() protected void simpleInitGame() {

      audio = AudioSystem.getSystem();
      audio.getEar().trackOrientation(cam);
      audio.getEar().trackPosition(cam);

      AudioTrack music = getDynamic();
      
      audio.getEnvironmentalPool().addTrack(music);
   }
   
   private AudioTrack getDynamic() {
      return new DynamicAudioTrack();
   }


   @Override() protected void simpleUpdate() {
      audio.update();
   }

   @Override() protected void cleanup() {
      audio.cleanup();
   }
   
}

1 Like

"Sounds" cool.  :P  Can you provide a simple test app showing it off?  That would make it a lot easier to add to jME.

the above code is actually a runnable app.  it generates static noise by:



      @Override public int read(ByteBuffer b, int offset, int length)   throws IOException {
         //System.out.println("read: " + b+ " " + offset + " " + length);
         
         for (int i = offset; i < length; i++) {
            b.put(i, (byte)(Math.random() * 200));
         }
         return length;
      }



i'm using this to convert a double[] audio stream to bytes:


         for (int i = offset; i < offset+length; ) {
            double[] s = generator.nextSample();
            
            int l = (int)(s[0] * shortMax);
            int r = (int)(s[1] * shortMax);
            
            byte l1 = (byte)((l >> 8) & 0xFF);
            byte l2 =  (byte)(l & 0xFF);

            byte r1 = (byte)((r >> 8) & 0xFF);
            byte r2 = (byte)(r & 0xFF);
            
            b.put(i++, l1);
            b.put(i++, l2);
            b.put(i++, r1);
            b.put(i++, r2);
         }



where double[] is a 2-element array representing the left & right sample values.  sample amplitude may need to be adjusted to be within audible range, otherwise it will be clipped/distorted.

reply if more information will be helpful...

Oh sorry, when you said "so this code subclasses AudioInputStream into DynamicAudioStream" I immediately saw that as the only function of the code.  doh.

If you don't mind I'd like to clean this up a little and add this as a real test.

absolutely, please do