Class SamplePlayingInstrument

java.lang.Object
All Implemented Interfaces:
Editable, Instrument, Namable, OutputProvider, Transposable, AttributeBuildable, DirectorySettable, HandleSpecialXMLTag, Tunable
Direct Known Subclasses:
SimpleSamplePlayingInstrumentWithAmplitudeMap, SupoveVox, TransposingSamplePlayingInstrumentWithAmplitudeMap

public class SamplePlayingInstrument
extends JSynSimpleUnitVoiceInstrument
implements AttributeBuildable, DirectorySettable, HandleSpecialXMLTag, Editable
A JMSL Instrument that plays audio samples, mapped to integer pitch values.
It has three modes of playing back a sample: SAMPLE_ONE_SHOT, SAMPLE_LOOPING, and SAMPLE_CROSSFADED_LOOPING.
SAMPLE_ONE_SHOT is for percussive sounds that just get played through once. The others are for sustainable sounds, and require the audio sample to contain two markers that the instrument will use to loop between.

If loadSample() fails to find it it will open a SampleFinderDialog.

It gets its numChannels by inspecting the audio files (1 or 2)

IMPORTANT: For Applets, the root sample directory passed to the constructor is ignored and CODEBASE is used instead!!!! So your samples should be in your applet's CODEBASE. The use of subfolders is ok, just make everything relative to CODEBASE. So for example, if locally you have a root sample directory called D:/Samples/ relative to which all your samples are located, and inside it is hr16_stereo/AlesisKick.aif, then your applet's CODEBASE, which might be a folder called "classes", should contain hr16_stereo/AlesisKick.aif
 SamplePlayingInstrument ins = new SamplePlayingInstrument("D:\\Samples\\");
 
 ins.getMusicDevice().edit(f);
 ins.getMusicDevice().open();
 
 ins.addSamplePitch("hr16_stereo\\AlesisKick.aif", 60);
 ins.addSamplePitch("hr16_stereo\\AlesisSnare.aif", 61);
 ins.addSamplePitch("hr16_stereo\\AlesisFloorTom.aif", 62);
 ins.addSamplePitch("hr16_stereo\\AlesisRackTom1.aif", 63);
 ins.addSamplePitch("hr16_stereo\\AlesisRackTom2.aif", 64);
 ins.buildFromAttributes();
 
 JMSLMixerContainer mixer = new JMSLMixerContainer();
 mixer.addInstrument(ins);
 mixer.start();
 
 
Author:
Nick Didkovsky, nick@didkovsky.com (C) 2012 Nick Didkovsky, all rights reserved.
  • Field Details

    • POLYPHONY

      public int POLYPHONY
      max number of voices to allocate, default 16. You may this change before creating new instances of this class and its subclasses
    • SAMPLE_ONE_SHOT

      public static final int SAMPLE_ONE_SHOT
      See Also:
      Constant Field Values
    • SAMPLE_LOOPING

      public static final int SAMPLE_LOOPING
      See Also:
      Constant Field Values
    • SAMPLE_CROSSFADED_LOOPING

      public static final int SAMPLE_CROSSFADED_LOOPING
      See Also:
      Constant Field Values
  • Constructor Details

    • SamplePlayingInstrument

      public SamplePlayingInstrument()
    • SamplePlayingInstrument

      public SamplePlayingInstrument​(java.lang.String sampleDirectory)
      All samples will be sought in this directory. They can be in subfolders, but all must be relative to this dir.
  • Method Details

    • getPlaybackMode

      public int getPlaybackMode()
    • setPlaybackMode

      public void setPlaybackMode​(int playbackMode)
    • clear

      public void clear()
      remove all samples and pitch mappings
    • open

      public double open​(double time) throws java.lang.InterruptedException
      Specified by:
      open in interface Instrument
      Overrides:
      open in class InstrumentAdapter
      Throws:
      java.lang.InterruptedException
    • close

      public double close​(double time) throws java.lang.InterruptedException
      Specified by:
      close in interface Instrument
      Overrides:
      close in class InstrumentAdapter
      Throws:
      java.lang.InterruptedException
    • setDirectory

      public void setDirectory​(java.io.File dir)
      Specified by:
      setDirectory in interface DirectorySettable
    • getDirectory

      public java.io.File getDirectory()
      Specified by:
      getDirectory in interface DirectorySettable
    • getSampleDirectoryName

      public java.lang.String getSampleDirectoryName()
      Returns:
      the sampleDirectoryName
    • setSampleDirectoryName

      public void setSampleDirectoryName​(java.lang.String sampleDirectoryName)
      Parameters:
      sampleDirectoryName - the sampleDirectoryName to set
    • testSampleDirectory

      public void testSampleDirectory()
    • reload

      public void reload()
    • getNumOutputs

      public int getNumOutputs()
      Specified by:
      getNumOutputs in interface OutputProvider
      Overrides:
      getNumOutputs in class JSynSimpleUnitVoiceInstrument
      Returns:
      1 or 2, derived from audio samples loaded (mono or stereo) . Setter is meaningless, this is calculated
    • addSamplePitch

      public void addSamplePitch​(java.lang.String filename, int pitch)
      Assign a sample to be triggered when noteIndex is passed to play().
      For example, let's say all your samples are in C:\mysamples\
      You pass "C:\mysamples\" to the constructor.
      Let's say C:\mysamples\ contains a directory called DrumMachine which contains snare.wav
      Then you would call addSamplePitch() with "DrumMachine/snare.wav" since that is its location relative to C:\mysamples\ The recommended way to subclass this instrument is to override buildFromAttributes, making multiple calls to addSamplePitch() first, finally calling super.buildFromAttributes()
    • addSamplePitch

      public void addSamplePitch​(com.jsyn.data.AudioSample sample, int pitch)
      Assign a dynamically created sample to a note index. If you do this you will not be able to save/reload. You are committed to runtime building
    • addSamplePitch

      public void addSamplePitch​(float[] floats, int pitch, int channelsPerFrame)
      Assign a dynamically created sample to a note index. If you do this you will not be able to save/reload from file. You are committed to runtime building
    • addSamplePitch

      public void addSamplePitch​(short[] shorts, int pitch, int channelsPerFrame)
      Assign a dynamically created sample to a note index. If you do this you will not be able to save/reload from file. You are committed to runtime building
    • removeSample

      public void removeSample​(int pitch)
    • getSampleFilename

      public java.lang.String getSampleFilename​(int pitch)
    • allSamplesSameNumberOfChannels

      public boolean allSamplesSameNumberOfChannels()
    • getAudioSamples

      public java.util.Hashtable getAudioSamples()
      Returns:
      hashtable of (Integer) pitchindex keys and AudioSample values
    • getPitches

      public int[] getPitches()
      Returns:
      sorted array of pitches which have been assigned to audio samples
    • getAlternativeSampleIndex

      public int getAlternativeSampleIndex​(int pitchIndex, double timeStretch, double[] data)
      Precondition: pitchIndex points to a valid sample, previously loaded with addSamplePitch(). Override this method to point to a different valid sample index. For example, you might store a loud sample at pitchIndex 60 and quiet sample at index 200 (ie some pitch index you'd never bang directly), and if the amplitude of data[] < 0.3 return 200 for this pitchIndex, else return 60)
      Returns:
      valid index to use instead of pitchIndex. This default version returns incoming pitchIndex
    • play

      public double play​(double playTime, double timeStretch, double[] dar)
      Description copied from class: InstrumentAdapter
      You can override this play() method with your own custom code, if you don't want to use an interpreter. Be sure to return same or updated playTime!
      Source of default implementation of play():
              public double play(double playTime, double timeStretch, double dar[])
              {
                      if (interpreter != null) playTime = interpreter.interpret(playTime, timeStretch, dar, this );
                      return playTime; // note: if interpreter == null, this will return a playTime with no time delay.
              }       
              
      IMPORTANT: A typical return would be return playTime + dar[0] * timeStretch; which follows a convention of putting duration value in dar[0]. If you don't add something to playTime, play() will be scheduled as though it took no time (unless interpreter returns a later playTime).

      RE-EMPHASIS: This return comment assumes that there is no interpreter returning an updated playTime. A stock Instrument does set its Interpreter to a default printing Interpreter which does update playTime, using dar[0] as duration. So the default Instrument.play() shown above will schedule itself as expected.
      Specified by:
      play in interface Instrument
      Overrides:
      play in class JSynSimpleUnitVoiceInstrument
    • on

      public java.lang.Object on​(double playTime, double timeStretch, double[] dar)
      Turn on a sample, return voice token to access VoiceAllocator.
      Specified by:
      on in interface Instrument
      Overrides:
      on in class InstrumentAdapter
      Returns:
      new Integer(voiceToken)
      See Also:
      Instrument.on(double, double, double[])
    • off

      public void off​(java.lang.Object voiceToken, double offTime)
      use this to turn off a sustaining sample that was initiated with on() which returns Integer(voiceToken)
    • off

      public java.lang.Object off​(double playTime, double timeStretch, double[] dar)
      not used, use public void off(int voiceToken, double offTime) instead, get voiceToken from on() which returns Integer(voiceToken)
      Specified by:
      off in interface Instrument
      Overrides:
      off in class InstrumentAdapter
      Returns:
      null
      See Also:
      com.softsynth.jmsl.Instrument#off(double, Object)
    • buildFromAttributes

      public void buildFromAttributes()
      Specified by:
      buildFromAttributes in interface AttributeBuildable
      Overrides:
      buildFromAttributes in class JSynSimpleUnitVoiceInstrument
    • setVoiceAllocatorUnitVoiceName

      public void setVoiceAllocatorUnitVoiceName()
    • toString

      public java.lang.String toString()
      Overrides:
      toString in class InstrumentAdapter
    • getTuning

      public Tuning getTuning()
      Specified by:
      getTuning in interface Tunable
      Overrides:
      getTuning in class JSynSimpleUnitVoiceInstrument
      Returns:
      tuning stored in this instrument. Not used to perform.
    • setTuning

      public void setTuning​(Tuning tuning)
      Specified by:
      setTuning in interface Tunable
      Overrides:
      setTuning in class JSynSimpleUnitVoiceInstrument
      Parameters:
      tuning - to be stored in this instrument. Not used to perform.
    • handleSpecialTag

      public boolean handleSpecialTag​(java.lang.String tag, java.util.Hashtable attributes)
      HandleSpecialXMLTag interface. Store pitch / soundfilename pairs for loading later
      Specified by:
      handleSpecialTag in interface HandleSpecialXMLTag
      Returns:
      true if this tag is recognized as special, false if the object permits normal bean model to handle attribute/value pairs
      See Also:
      HandleSpecialXMLTag.handleSpecialTag(java.lang.String, java.util.Hashtable)
    • writeSpecialXMLTags

      public void writeSpecialXMLTags​(java.io.PrintWriter out) throws java.io.IOException
      write pitch / soundfilename pairs to XML file These are not covered by simple bean model since there are many such pairs.
      Specified by:
      writeSpecialXMLTags in interface HandleSpecialXMLTag
      Throws:
      java.io.IOException
      See Also:
      HandleSpecialXMLTag.writeSpecialXMLTags(java.io.PrintWriter)
    • notifyEditListeners

      public void notifyEditListeners()
    • addEditListener

      public void addEditListener​(EditListener listener)
      Specified by:
      addEditListener in interface Editable
    • removeEditListener

      public void removeEditListener​(EditListener listener)
      Specified by:
      removeEditListener in interface Editable
    • edit

      public void edit​(java.awt.Frame fr)
      Open a Frame containing a SampleInstrumentMapperPanel for this instrument.
      Specified by:
      edit in interface Editable
      See Also:
      Editable.edit(java.awt.Frame)
    • setEditEnabled

      public void setEditEnabled​(boolean flag)
      noop
      Specified by:
      setEditEnabled in interface Editable
      See Also:
      Editable.setEditEnabled(boolean)
    • getEditEnabled

      public boolean getEditEnabled()
      Specified by:
      getEditEnabled in interface Editable
      Returns:
      true
    • main

      public static void main​(java.lang.String[] args)