Sound Creation
Weber.sound
— Function.sound(x::Array,[cache=true];[sample_rate=samplerate()])
Creates a sound object from an arbitrary array.
Assumes 1 is the loudest and -1 the softest. The array should be 1d for mono signals, or an array of size (N,2) for stereo sounds.
When cache is set to true, sound will cache its results thus avoiding repeatedly creating a new sound for the same object.
This function is normally called implicitly in a call to play(x)
, so it need not normally be called directly.
sound(file,[cache=true];[sample_rate=samplerate(file)])
Load a specified file as a sound.
sound(stream,[len])
Consume some amount of the stream, converting it to a finite sound
.
If left unspecified, the entire stream is consumed. Infinite streams throw an error.
Weber.tone
— Function.tone(freq,length;[sample_rate=samplerate()],[phase=0])
Creates a pure tone of the given frequency and length (in seconds).
You can create an infinitely long tone by passing a length of Inf, or leaving out the length entirely.
Weber.noise
— Function.noise(length=Inf;[sample_rate_Hz=44100],[rng=RandomDevice()])
Creates a period of white noise of the given length (in seconds).
You can create an infinite stream of noise by passing a length of Inf, or leaving out the length entirely.
Weber.silence
— Function.silence(length;[sample_rate=samplerate()])
Creates period of silence of the given length (in seconds).
Weber.harmonic_complex
— Function.harmonic_complex(f0,harmonics,amps,length,
[sample_rate=samplerate()],[phases=zeros(length(harmonics))])
Creates a harmonic complex of the given length, with the specified harmonics at the given amplitudes. This implementation is somewhat superior to simply summing a number of pure tones generated using tone
, because it avoids beating in the sound that may occur due floating point errors.
You can create an infinitely long complex by passing a length of Inf, or leaving out the length entirely.
Weber.irn
— Function.irn(n,λ,[length=Inf];[g=1],[sample_rate=samplerate()],
[rng=Base.GLOBAL_RNG])
Creates an iterated ripple $y_n(t)$ for a noise $y_0(t)$ according to the following formula.
$y_n(t) = y_{n-1}(t) + g⋅y_{n-1}(t-d)$
You can create an infinitely long IRN by passing a length of Inf, or leaving out the length entirely.
For the streaming implementation, the noise's RNG is copied to generate the iterations, so copying this RNG must reliabley reproduce the same sequence of noise. This means you cannot use RandomDevice
.
Weber.audible
— Function.audible(fn,len=Inf,asseconds=true;[sample_rate=samplerate(),eltype=Float64])
Creates monaural sound where fn(t)
returns the amplitudes for a given Range
of time points, value ranging between -1 and 1.
If asseconds
is false, audible
creates a monaural sound where fn(i)
returns the amplitudes for a given Range
of sample indices.
The function fn
should always return elements of type eltype
.
If an infinite length is specified, a stream is created rather than a sound.
The function fn
need not be pure and it can be safely assumed that fn
will only be called for a given range of indices once. While indices and times passed to fn
normally begin from 1 and 0, respectively, this is not always the case.
Sound Manipulation
Weber.highpass
— Function.highpass(x,high,[order=5],[sample_rate_Hz=samplerate(x)])
High-pass filter the sound (or stream) at the specified frequency.
Filtering uses a butterworth filter of the given order.
Weber.lowpass
— Function.lowpass(x,low,[order=5],[sample_rate_Hz=samplerate(x)])
Low-pass filter the sound (or stream) at the specified frequency.
Filtering uses a butterworth filter of the given order.
Weber.bandpass
— Function.bandpass(x,low,high;[order=5])
Band-pass filter the sound (or stream) at the specified frequencies.
Filtering uses a butterworth filter of the given order.
Weber.bandstop
— Function.bandstop(x,low,high,[order=5],[sample_rate_Hz=samplerate(x)])
Band-stop filter of the sound (or stream) at the specified frequencies.
Filtering uses a butterworth filter of the given order.
Weber.ramp
— Function.ramp(x,[length=5ms])
Applies a half cosine ramp to start and end of the sound.
Ramps prevent clicks at the start and end of sounds.
Weber.rampon
— Function.rampon(stream,[len=5ms])
Applies a half consine ramp to start of the sound or stream.
Weber.rampoff
— Function.rampoff(stream,[len=5ms],[after=len])
Applies a half consine ramp to the end sound, or to a stream.
For streams, you can specify how many seconds after the newly modified stream begins playing the rampoff should finish.
Weber.fadeto
— Function.fadeto(a,b,[transition=50ms],[after=overlap])
A smooth transition from a to b, overlapping the end of one with the start of the other by overlap
.
For streams you can specify how long after the newly modified stream begins playing the transition should finish.
Weber.attenuate
— Function.attenuate(x,atten_dB;[time_constant])
Apply the given decibels of attenuation to the sound (or stream) relative to a power level of 1.
This function normalizes the sound to have a root mean squared value of 1 and then reduces the sound by a factor of $10^{-a/20}$, where $a$ = atten_dB
.
The keyword argument time_constant
determines the time across which the sound is normalized to power 1, which, for sounds, defaults to the entire sound and, for streams, defaults to 1 second.
Weber.mix
— Function.mix(x,y,...)
mix several sounds (or streams) together so that they play at the same time.
Unlike normal addition, this acts as if each sound is padded with zeros at the end so that the lengths of all sounds match.
Weber.mult
— Function.mult(x,y,...)
Mutliply several sounds (or streams) together. Typically used to apply an amplitude envelope.
Unlike normal multiplication, this acts as if each sound is padded with ones at the end so that the lengths of all sounds match.
Weber.envelope
— Function.envelope(mult,length;[sample_rate_Hz=44100])
creates an envelope of a given multiplier and length (in seconds).
If mult = 0 this is the same as calling silence
. This function is useful in conjunction with fadeto
and mult
when defining an envelope that changes in level. For example, the following will play a 1kHz tone for 1 second, which changes in volume halfway through to a softer level.
mult(tone(1000,1),fadeto(envelope(1,0.5),envelope(0.1,0.5)))
Weber.duration
— Function.duration(x)
Get the duration of the given sound in seconds.
Weber.nchannels
— Method.nchannels(sound)
Return the number of channels (1 for mono, 2 for stereo) in this sound.
Distributions.nsamples
— Method.nsamples(sound::Sound)
Returns the number of samples in the sound.
Weber.audiofn
— Function.audiofn(fn,x)
Apply fn
to x for both sounds and streams.
For a sound this is the same as calling fn(x)
.
For a stream, fn
will be applied to each unit of sound as it is requested from the stream.
Weber.leftright
— Function.leftright(left,right)
Create a stereo sound from two vectors or two monaural sounds.
For vectors, one can specify a sample_rate other than the default, if desired.
Weber.left
— Function.left(sound::Sound)
Extract the left channel a stereo sound or stream.
Weber.right
— Function.right(sound::Sound)
Extract the right channel of a stereo sound or stream.
Playback
Weber.play
— Function.play(x;[channel=0],[time=0s])
Plays a sound (created via sound
).
For convenience, play can also can be called on any object that can be turned into a sound (via sound
).
If a time is specified, it indicates the amount of time since epoch that the sound should start playing (see precise_time
).
This function returns immediately with the channel the sound is playing on. You may provide a specific channel that the sound plays on: only one sound can be played per channel. Normally it is unecessary to specify a channel, because an appropriate channel is selected for you. However, pausing and resuming of sounds occurs on a per channel basis, so if you plan to pause a specific sound, you can do so by specifying its channel.
Streams
Play can also be used to present a continuous stream of sound. In this case, the channel defaults to channel 1 (there is no automatic selection of channels for streams). Streams are usually created by specifying an infinite length during sound generation using tone
, noise
, harmonic_complex
or audible
.
play(fn::Function)
Play the sound that's returned by calling fn
.
Weber.setup_sound
— Function.setup_sound(;[sample_rate=samplerate()],[num_channels=8],[queue_size=8],
[stream_unit=2^11])
Initialize format and capacity of audio playback.
This function is called automatically (using the default settings) the first time a Sound
object is created (e.g. during play
). It need not normally be called explicitly, unless you wish to change one of the default settings.
Sample Rate
Sample rate determines the maximum playable frequency (max freq is ≈ sample_rate/2). Changing the sample rate from the default 44100 to a new value will also change the default sample rate sounds will be created at, to match this new sample rate.
Channel Number
The number of channels determines the number of sounds and streams that can be played concurrently. Note that discrete sounds and streams use a distinct set of channels.
Queue Size
Sounds can be queued to play ahead of time (using the time
parameter of play
). When you request that a sound be played it may be queued to play on a channel where a sound is already playing. The number of sounds that can be queued to play at once is determined by queue size. The number of channels times the queue size determines the number of sounds that you can queue up to play ahead of time.
Stream Unit
The stream unit determines the number of samples that are streamed at one time. If this value is too small for your hardware, streams will sound jumpy. However the latency of streams will increase as the stream unit increases.
Weber.playable
— Function.playable(x,[cache=true],[sample_rate=samplerate()])
Prepare a sound or stream to be played.
A call to playable
will ensure the sound is in the format required by play
. This automatically calls sound
on x
if it does not appear to already be a sound or a stream.
This need not be called explicitly, as play will call it for you, if need be.
DSP.Filters.resample
— Method.resample(x::Sound,samplerate)
Returns a new sound representing the sound x
at the given sampling rate.
You will loose all frequencies in the sound above samplerate/2. Resampling occurs automatically when you call sound
–which is called inside play
–anytime the sampling rate of the sound and the current audio playback settings (determined by setup_sound
) are not the same.
To avoid automatic resampling you can either create sounds at the appropriate sampling rate, as determined by samplerate
(recommended), or change the sampling rate initialized during setup_sound
(not recommended).
Weber.stop
— Function.stop(channel)
Stop the stream that is playing on the given channel.
SampledSignals.samplerate
— Function.samplerate([sound])
Report the sampling rate of the sound or of any object that can be turned into a sound.
The sampling rate of an object determines how many samples per second are used to represent the sound. Objects that can be converted to sounds are assumed to be at the sampling rate of the current hardware settings as defined by setup_sound
.
With no argument samplerate reports the current playback sample rate, as defined by setup_sound
.
Weber.current_sound_latency
— Function.current_sound_latency()
Reports the current, minimum latency of audio playback.
The current latency depends on your hardware and software drivers. This estimate does not include the time it takes for a sound to travel from your sound card to speakers or headphones. This latency estimate is used internally by play
to present sounds at accurate times.
Weber.pause_sounds
— Function.pause_sounds([channel],[isstream=false])
Pause all sounds (or a stream) playing on a given channel.
If no channel is specified, then all sounds are paused.
Weber.resume_sounds
— Function.resume_sounds([channel],[isstream=false])
Resume all sounds (or a stream) playing on a given channel.
If no channel is specified, then all sounds are resumed.
Weber.run_calibrate
— Function.run_calibrate()
Runs a program that will allow you to play pure tones and adjust their level.
This program provides one means of calibrating the levels of sound in your experiment. Using a sound-level meter you can determine the dB SPL of each tone, and adjust the attenuation to achieve a desired sound level.