Package com.softsynth.jmsl.jsyn2
Class SamplePlayingInstrument
java.lang.Object
com.softsynth.jmsl.InstrumentAdapter
com.softsynth.jmsl.jsyn2.JSynSimpleUnitVoiceInstrument
com.softsynth.jmsl.jsyn2.SamplePlayingInstrument
- 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
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 Summary
Fields Modifier and Type Field Description int
POLYPHONY
max number of voices to allocate, default 16.static int
SAMPLE_CROSSFADED_LOOPING
static int
SAMPLE_LOOPING
static int
SAMPLE_ONE_SHOT
-
Constructor Summary
Constructors Constructor Description SamplePlayingInstrument()
SamplePlayingInstrument(java.lang.String sampleDirectory)
All samples will be sought in this directory. -
Method Summary
Modifier and Type Method Description void
addEditListener(EditListener listener)
void
addSamplePitch(float[] floats, int pitch, int channelsPerFrame)
Assign a dynamically created sample to a note index.void
addSamplePitch(short[] shorts, int pitch, int channelsPerFrame)
Assign a dynamically created sample to a note index.void
addSamplePitch(com.jsyn.data.AudioSample sample, int pitch)
Assign a dynamically created sample to a note index.void
addSamplePitch(java.lang.String filename, int pitch)
Assign a sample to be triggered when noteIndex is passed to play().boolean
allSamplesSameNumberOfChannels()
void
buildFromAttributes()
void
clear()
remove all samples and pitch mappingsdouble
close(double time)
void
edit(java.awt.Frame fr)
Open a Frame containing a SampleInstrumentMapperPanel for this instrument.int
getAlternativeSampleIndex(int pitchIndex, double timeStretch, double[] data)
Precondition: pitchIndex points to a valid sample, previously loaded with addSamplePitch().java.util.Hashtable
getAudioSamples()
java.io.File
getDirectory()
boolean
getEditEnabled()
int
getNumOutputs()
int[]
getPitches()
int
getPlaybackMode()
java.lang.String
getSampleDirectoryName()
java.lang.String
getSampleFilename(int pitch)
Tuning
getTuning()
boolean
handleSpecialTag(java.lang.String tag, java.util.Hashtable attributes)
HandleSpecialXMLTag interface.static void
main(java.lang.String[] args)
void
notifyEditListeners()
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)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)java.lang.Object
on(double playTime, double timeStretch, double[] dar)
Turn on a sample, return voice token to access VoiceAllocator.double
open(double time)
double
play(double playTime, double timeStretch, double[] dar)
You can override this play() method with your own custom code, if you don't want to use an interpreter.void
reload()
void
removeEditListener(EditListener listener)
void
removeSample(int pitch)
void
setDirectory(java.io.File dir)
void
setEditEnabled(boolean flag)
noopvoid
setPlaybackMode(int playbackMode)
void
setSampleDirectoryName(java.lang.String sampleDirectoryName)
void
setTuning(Tuning tuning)
void
setVoiceAllocatorUnitVoiceName()
void
testSampleDirectory()
java.lang.String
toString()
void
writeSpecialXMLTags(java.io.PrintWriter out)
write pitch / soundfilename pairs to XML file These are not covered by simple bean model since there are many such pairs.Methods inherited from class com.softsynth.jmsl.jsyn2.JSynSimpleUnitVoiceInstrument
addSignalSource, getOutput, getOutput, getPolyphony, getPreset, getUnitVoiceArray, getUnitVoiceClassName, getVoiceAllocator, isSignalProcessor, removeAllSignalSources, setPolyphony, setPreset, setUnitVoiceClassName
Methods inherited from class com.softsynth.jmsl.InstrumentAdapter
getDimensionNameSpace, getInterpreter, getMixerClassName, getMusicDevice, getName, getTransposition, noteOff, noteOn, noteOnFor, setDimensionNameSpace, setInterpreter, setMixerClassName, setMusicDevice, setName, setTransposition, update
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, wait, wait, wait
-
Field Details
-
POLYPHONY
public int POLYPHONYmax 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 interfaceInstrument
- Overrides:
open
in classInstrumentAdapter
- Throws:
java.lang.InterruptedException
-
close
public double close(double time) throws java.lang.InterruptedException- Specified by:
close
in interfaceInstrument
- Overrides:
close
in classInstrumentAdapter
- Throws:
java.lang.InterruptedException
-
setDirectory
public void setDirectory(java.io.File dir)- Specified by:
setDirectory
in interfaceDirectorySettable
-
getDirectory
public java.io.File getDirectory()- Specified by:
getDirectory
in interfaceDirectorySettable
-
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 interfaceOutputProvider
- Overrides:
getNumOutputs
in classJSynSimpleUnitVoiceInstrument
- 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 interfaceInstrument
- Overrides:
play
in classJSynSimpleUnitVoiceInstrument
-
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 interfaceInstrument
- Overrides:
on
in classInstrumentAdapter
- 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 interfaceInstrument
- Overrides:
off
in classInstrumentAdapter
- Returns:
- null
- See Also:
com.softsynth.jmsl.Instrument#off(double, Object)
-
buildFromAttributes
public void buildFromAttributes()- Specified by:
buildFromAttributes
in interfaceAttributeBuildable
- Overrides:
buildFromAttributes
in classJSynSimpleUnitVoiceInstrument
-
setVoiceAllocatorUnitVoiceName
public void setVoiceAllocatorUnitVoiceName() -
toString
public java.lang.String toString()- Overrides:
toString
in classInstrumentAdapter
-
getTuning
- Specified by:
getTuning
in interfaceTunable
- Overrides:
getTuning
in classJSynSimpleUnitVoiceInstrument
- Returns:
- tuning stored in this instrument. Not used to perform.
-
setTuning
- Specified by:
setTuning
in interfaceTunable
- Overrides:
setTuning
in classJSynSimpleUnitVoiceInstrument
- 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 interfaceHandleSpecialXMLTag
- 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.IOExceptionwrite pitch / soundfilename pairs to XML file These are not covered by simple bean model since there are many such pairs.- Specified by:
writeSpecialXMLTags
in interfaceHandleSpecialXMLTag
- Throws:
java.io.IOException
- See Also:
HandleSpecialXMLTag.writeSpecialXMLTags(java.io.PrintWriter)
-
notifyEditListeners
public void notifyEditListeners() -
addEditListener
- Specified by:
addEditListener
in interfaceEditable
-
removeEditListener
- Specified by:
removeEditListener
in interfaceEditable
-
edit
public void edit(java.awt.Frame fr)Open a Frame containing a SampleInstrumentMapperPanel for this instrument.- Specified by:
edit
in interfaceEditable
- See Also:
Editable.edit(java.awt.Frame)
-
setEditEnabled
public void setEditEnabled(boolean flag)noop- Specified by:
setEditEnabled
in interfaceEditable
- See Also:
Editable.setEditEnabled(boolean)
-
getEditEnabled
public boolean getEditEnabled()- Specified by:
getEditEnabled
in interfaceEditable
- Returns:
- true
-
main
public static void main(java.lang.String[] args)
-