The Player class
- class audiomath.Player(sound, device=None, stream=None, bufferLengthMsec=None, minLatencyMsec=None, fs=None, resample=False, verbose=None, **kwargs)
Bases:
GenericPlayerA
Playerprovides a persistent connection to the chosen playback hardware, allowing aSoundinstance to be played.A
Playerinstance can only play oneSoundat a time, but it can optionally maintain a list ofSoundinstances in aQueueand switch between them. For overlapping sounds, use multiplePlayerinstances.A
Playerinstance can be created directly from a filename, list of filenames or filename glob pattern. The currentSoundinstance is available in thesoundproperty and the completeQueueis available in thequeueproperty.It is better to create a
Playerinstance than to rely on the quick-and-dirtyPlay()methods of theSoundandQueueclasses—these methods just create aPlayer(entailing some computational overhead), wait synchronously for it to finish, and then destroy it again. Creating your ownPlayerinstance provides much greater flexibility and performance.- Parameters:
sound (str, Sound, Queue, None) –
Soundinstance to play (or sequence ofSoundinstances in alistorQueue). Alternatively, supply any argument that is also a valid input to theSoundorQueueconstructors (e.g. a filename, list of filenames, or file glob pattern).device (int, str, dict, Stream, None) – Optionally use this argument to specify the device/stream to use for playback—as an integer index, a device name, a full device record from
FindDevice(), or (fastest of all) an already-openStreaminstance.stream (int, str, dict, Stream, None) – Synonymous with
device, for compatibility.bufferLengthMsec (float, None, ‘auto’) – Optionally specify a buffer length in milliseconds when creating your first
Playeror firstStream(after that,Playerinstances may share an openStreaminstance so it is possible that only the first call will make any difference). Larger buffer lengths lead to higher playback latencies.Nonemeans use whatever is currently globally configured inPORTAUDIO.DEFAULT_BUFFER_LENGTH_MSEC.'auto'or'pa-default'means use the default supplied by the PortAudio library.minLatencyMsec (float, None, ‘auto’) – Use this setting to override the PortAudio default for “suggested” latency when creating a
Stream. The values supplied here typically undershoot the empirically measurable latency (in a non-linear fashion) but larger values mean greater robustness (less crackle/stutter susceptibility) at the cost of longer latencies and higher jitter.Nonemeans use whatever is currently globally configured inPORTAUDIO.DEFAULT_MIN_LATENCY_MSEC.'auto'means use certain defaults that we have empirically derived to balance these factors.'pa-default'means use the defaults supplied by the PortAudio library.fs (float, None) – Optionally specify the sampling frequency, in Hz, when creating your first
Playeror firstStream(after that,Playerinstances may share an openStreaminstance so it is possible that only the first call will make any difference).resample (bool) – Specifies how to handle potential mismatch between the sampling frequency of the sound data
self.sound.fsand the sampling frequency of the output streamself.stream.fs. If true, replaceself.soundwith a copy resampled to the stream’s preferred rate. If false, simply adjust playback speed accordingly (at a small, ongoing, computational cost).verbose (bool, None) – Verbosity for debugging. If
None, inherit from the setting specified bySetDefaultVerbosity(), if any.**kwargs – passed through to
Set()to initialize properties of thePlayerinstance.
- GetDynamic(name)
For dynamic properties, return the actual callable object that generates property values, rather than the current static value.
- Parameters:
name (str) – Name of the property
- Returns:
Callable object responsible for generating values for the named property (or
Noneif there is no such dynamic).
Example:
import audiomath as am, numpy as np p = am.Player(am.TestSound('12'), loop=True, playing=True) p.volume = lambda t: 0.5+0.5*np.sin(2.0*np.pi*t*0.25) v = p.volume # this retrieves a float f = p.GetDynamic('volume') # this retrieves the lambda
- NextTrack(count=1, raiseException=True)
Jump to the beginning of the next track in the
queueand return the correspondingSoundinstance.If this entails going beyond the last track, raise an exception unless
raiseException=False(in which case go to the beginning of the last track, stop playing, and returnNone).
- Pause(position=None, **kwargs)
Stop playing. Optionally change the
headposition to the specified absolutepositionin seconds, ready for subsequent playback. Optionally, use keyword arguments to set additional properties (e.g.volume,pan,levels,speed,loop, etc) at the same time.
- Play(position=None, wait=False, **kwargs)
Start playing. Optionally use
positionto specify the exactheadposition from which to start playing (in seconds from the beginning of the currentsound). Otherwise playack starts from wherever it last ended up (or at the beginning, if the sound previously ran to the end).If you call
p.Play()without an explicitpositionon an instancepthat is already playing, nothing changes—playback simply continues. In this sense it is equivalent to manipulating theplayingproperty by sayingp.playing = True.If
waitis true, immediately callWait()so that playback is synchronous.Optionally, use further keyword arguments to set additional properties (e.g.
volume,pan,levels,speed,loop,track, etc) at the same time.
- PreviousTrack(count=1, raiseException=True)
Jump to the beginning of the track prior to the current one in the
queueand return the correspondingSoundinstance.If this entails going back beyond the beginning, raise an exception unless
raiseException=False(in which case go to the beginning of the first track, stop playing, and returnNone).Unlike the “back” button on your music player, this does not go to the beginning of the current track before skipping to the previous track. To restart the current track, use
p.Play(0)orp.Seek(0)orp.head = 0
- Resample(newFs, wholeQueue=True)
Replace
self.soundwith a copy resampled at the new sampling ratenewFs. Also adjust the Player’s internal speed compensation factor, to ensure things sound the same on the existing stream. The most common usage will be to match the sound sample rate to the sample rate of the hardware (so the Player’s compensation factor becomes 1.0) to ensure more efficient playback.
- ResetDynamics(synchronized=None)
To restart the clock from which the dynamic properties of a
Playerinstancepare computed, resetting its “time zero” to the current time:p.ResetDynamics()
To set the
synchronizeDynamicspolicy at the same time, passTrueorFalseas the input argument.To synchronize
pto a global “time zero” that multiplePlayerinstances can share (hence, necessarily, unsynchronized with respect to the playing/pausing ofpitself):p.ResetDynamics('global')
See also:
dynamics,synchronizeDynamics
- Seek(position, relative=False)
Move the playback
headto the specifiedpositionin seconds. Negative values count back from the end ofself.sound. Ifrelativeis true,positionis interpreted as an offset relative to the current head position. The following are equivalent:p.Seek( 5.0, relative=False ) # more efficient p.head = 5.0
And the following are also equivalent:
p.Seek( -2.0, relative=True ) # more efficient p.head -= 2.0
- Set(**kwargs)
Set the values of multiple attributes or properties in one call. An error will be raised if you try to set the value of a non-existent attribute.
Note that the
Play()andPause()methods also allow you to set arbitrary properties prior to their manipulation ofplayingstatus.- Returns:
self
Example:
p.Set( head=0, loop=True, volume=0.5 )
- SetDynamic(name, func, order=1)
Associate a “dynamic” (i.e. a function that can be called repeatedly to set an attribute) with the name of an attribute.
For example:
foo.Set( 'bar', lambda t: t ** 2 )
This will set
foo.bartot ** 2every time the methodfoo._RunDynamics( t )is called (this call will happen automatically from the API user’s point of view, in the object’s infrastructure implementation).If the
barattribute happens to have been already configured as a “dynamic property” this means it supports “dynamic value assignment”, i.e. you can do:foo.bar = lambda t: t ** 2
as a syntactic shorthand for
SetDynamic()—the setter will detect the fact that the value is callable, and divert it to the register of dynamics rather than assigning it directly (so the actual static value you get from queryingfoo.barwill not immediately change).- Parameters:
name (str) – name of the attribute
func – callable object, or
Noneto remove any dynamic that may already be associated withnameorder (int, float) – optional numeric ordering key that allows you to control the serial order in which dynamics are evaluated
- Returns:
self
See also:
GetDynamic(),GetDynamics(),ClearDynamics()
- Stop(position=None, **kwargs)
Stop playing. Optionally change the
headposition to the specified absolutepositionin seconds, ready for subsequent playback. Optionally, use keyword arguments to set additional properties (e.g.volume,pan,levels,speed,loop, etc) at the same time.
- SwitchToTrack(position, raiseException=True, allowNegative=True)
Immediately jump to the sound at the given position in the
queue(equivalent to setting thetrackproperty).
- Wait()
Sleep until
selfstops playing, or until the user presses ctrl-C to interrupt.
- WaitFor(condition, finalPlayingStatus=None)
Sleep until
conditionis fulfilled. Theconditionargument may be:- a
Recorderinstance: in which case the method waits until the recorder is no longer recording;
- a
Playerinstance: in which case the method waits until the player is no longer playing;
- a string:
in which case the method will print the string as a prompt and wait for the user to enter press ctrl-C on the console;
- any callable:
in which case the method will repeatedly call
condition()between 1-ms sleeps until it returns anything other thanNone.
If
finalPlayingStatusis notNone, thenself.playingis set to its value when the wait is over. So for example, you can prompt a user to end ongoing playback as follows:p.WaitFor('Press ctrl-C to stop playing: ', finalPlayingStatus=False)
- a
- property autoAdvance
This property may take the following values:
False:when the current
soundfinishes playing, rewind theheadto the start of the current sound but do not advance through thequeue.Trueor'play':when the current
soundfinishes playing, continue to the nextSoundinstance in thequeue, if any.'pause':when the current
soundfinishes playing, advance to the nextSoundinstance in thequeue, if any, but pause playback.
autoAdvanceis a dynamic property (seedynamics).See also
- property dynamics
Many
Playerproperties, such asvolume,speed,pan,levelsand evenplaying, support “dynamic value assignment”. This means you can do something like the following:import audiomath as am p = am.Player(am.TestSound('12'), loop=True) p.volume = lambda t: min( 1.0, t / 5.0 ) p.Play()
When queried,
p.volumestill appears to be a floating-point number, but this value changes as a function of timetin seconds—in this example, the volume fades up from 0.0 to 1.0 over the course of five seconds.Dynamic functions are called automatically in the streaming callback. You should take care to make them as computationally lightweight and efficient as possible. Your functions may accept 0, 1 or 2 arguments. If they accept 1 argument, it is always time in seconds. If they accept 2 arguments, these will be the
Playerinstance first, followed by time in seconds.Time
tmay be synchronized with, or independent of, the playing/pausing status of thePlayeritself, according to thesynchronizeDynamicsproperty. “Time zero” may be reset, or synchronized with other players, usingResetDynamics().Dynamic functions may choose to terminate and remove themselves, by saying
raise StopIteration()or evenraise StopIteration(final_property_value)See also
synchronizeDynamics,ResetDynamics(),GetDynamic(),SetDynamic()
- property head
Current playback position, in seconds relative to the beginning.
You can change the playback position by assigning to
head, but note that it is fractionally faster/more efficient to do this by calling theSeek()method.
- property levels
This is an optional sequence of multipliers applied to each channel in turn. It is independent of (i.e. its effects simply get multiplied by the effects of) other properties that affect intensity, such as
volumeandpan
- property loop
This boolean-valued property determines whether the current sound should wrap around to the beginning when it finishes playing (NB: if you are looping, you will stay on the current
soundand never advance through thequeue).
- property muted
This is a boolean property that, if true, causes the
Playerto be silent, independent of the currentvolumeand/orlevels.
- property norm
For a
Playerinstancep, if you setp.panto a scalar value between -1 and +1, the relative levels of left and right channels are computed such that:left ** p.norm + right ** p.norm = 1
The value
p.norm=2produces a natural-sounding pan but it means that stereo sounds are reduced to 70.71% of their maximum amplitude by default. So instead, the default is to use the infinity-norm,p.norm='inf', which ensures that the larger of the two sides is always 1.0
- property pan
A value of -1 means left channels only, right channels silent. A value of 0 means left and right channels at equal volume. A value of +1 means right channels only, left channels silent.
The way levels are computed from scalar values between -1 and +1 depends on
norm. Alternatively, you can supply a two- element sequence that explicitly specifies[left, right]levels.Note that these levels are independent from (i.e. they are simply multiplied by) the overall
volumeand channel-by- channellevelssettings.
- property playing
This boolean property reflects, and determines, whether the
Playeris currently playing or paused.
- property queue
This special sequence of class
Queueprovides a list ofSoundinstances between which thePlayermay switch.The
Playerinstance’srepeatQueueandautoAdvanceproperties allow you to specify how the queue is used when a givenSoundfinishes playing. Thetrackproperty allows you to jump immediately to a given place in the queue.NB: direct manipulation of the queue, for example using its own methods
self.queue.Forward()orself.queue.Back(), will not affect whicheverself.soundis currently loaded into thePlayer, but they will affect what happens when that sound has finished playing. If you want to change tracks with immediate effect, you should instead use correspondingPlayermethodsself.NextTrack()orself.PreviousTrack(), or manipulate the propertyself.track.See also
autoAdvance,repeatQueue,track,NextTrack(),PreviousTrack()
- property repeatQueue
This boolean property is a shortcut to the sub-property
self.queue.loop. If true, then moving beyond either end of thequeuecauses a wrap-around to the other end.repeatQueueis a dynamic property (seedynamics).See also
- property sound
A reference to the
Soundinstance that thePlayeris currently playing, orNone. You can change it on-the-fly. It may also change automatically when the current sound finishes playing, if you have appended additionalSoundinstances thequeueand have set theautoAdvanceproperty.
- property speed
This floating-point property determines the speed at which the sound should be played. Normal speed is 1.0
- property synchronizeDynamics
Many
Playerproperties, such asvolume,speed,pan,levelsand evenplaying, can be dynamic, i.e. they can be set to functions of timetin seconds.If
p.synchronizeDynamicsis true, then the dynamic clock pauses whenever playback pauses and resumes only whenplayingbecomes true again. Hence, ifplayingitself is dynamic and becomes false, it will not be able to become true again on its own. So this example will only play once:import audiomath as am p = am.Player( am.TestSound( '12' ) ) p.Play( 0, loop = True, synchronizeDynamics = True, playing = lambda t: (t / p.sound.duration) % 2 < 1, )
If
p.synchronizeDynamicsis false, then the dynamic clock continues even when playback is paused. Hence, ifplayingis dynamic, thePlayercan stop and resume on a schedule. So the same example, with only a change to thesynchronizeDynamicssetting, will play repeatedly, with pauses:import audiomath as am p = am.Player( am.TestSound( '12' ) ) p.Play( 0, loop = True, synchronizeDynamics = False, playing = lambda t: (t / p.sound.duration) % 2 < 1, )
A separate but related issue is that of the “time zero” from which dynamic time
tis measured. By default, time zero for a givenPlayerinstancepis the time at whichpwas created. The clock can be reset by using theResetDynamics()method. You can also synchronizepwith a global clock, available to allPlayerinstances, by sayingp.ResetDynamics('global')See also:
dynamics,ResetDynamics()
- property track
If there are multiple items in the
queue, this property allows you to switch between them. You may use an integer zero-based index, aSoundinstance, or the stringlabelof that instance (provided the instance is already in thequeue)trackis a dynamic property (seedynamics).See also
autoAdvance,queue,repeatQueue,NextTrack(),PreviousTrack()
- property vol
This floating-point property is a multiplier for the amplitude of the sound waveforms. It is independent of (i.e. its effect simply gets multiplied by the effects of) other properties that affect channel-to- channel level differences, such as
levelsandpan