Transforms Guide - Quefumas/gensound GitHub Wiki
Transforms are objects that apply various effects or actions on existing Signals. Below we describe only the most essential Transforms available for import from gensound
or gensound.transforms
. Other than these, there are many more specialized Transforms, which will be described in dedicated pages in the wiki.
For defining new Transforms, see here.
Using Transforms
-
To apply a transform to a Signal, use the syntax:
SignalObject * TransformObject
. Gensound enforces that the Transform always be the right multiplicand, as this makes it visually easier to distinguish between the Signal and the Transform applied to it. (There is one exception to this syntax, see below) -
Transforms may be chained together:
SomeSignal()*Transform1()*Transform2()
; they will be applied in the same order to the Signal object. -
When using the same set of Transforms in conjunction very often, it is useful to give a shorter name:
my_effect = Transform1(...)*Transform2(...)*Transform3(...)
. The namemy_effect
may then be treated as any other Transform:SignalObject * my_effect
. -
Just like Signal objects, Transforms behave like immutable objects:
a = Transform1(...)
b = a
b *= Transform2(...) # 'a' remains unchanged
Volume/Level
Adjusting Amplitude
To scale the amplitude (i.e., volume) of a Signal object, left-multiply by a float
. This is a special syntax that is dedicated for this common case.
0.2*Sine() # Sine wave ranging from -0.2 to 0.2
This logic also generalizes to the following cases:
1*Sine() # has no effect
0*Sine() # will result in silence
-Sine() # inverts phase (will sounds the same if played as it is)
Sine() - Sine() # will result in silence
Adjusting Level (dBs)
To adjust the volume level using decibels (dBs) rather than amplitude, use the Gain
transform. dBs correlate much better than amplitude with our subjective perception of loudness.
s = WAV(test_wav)*Gain(-3)
s.play()
Gain
receives a single argument, the amount of dBs by which to adjust the volume.
Supplying a positive number will increase the volume by the specified amount of dBs, and a negative number will decrease it.
0
leaves the volume level unchanged, while the theoretical minimum of minus infinity would result in complete silence.
Fade in/out
The Transforms FadeIn
and FadeOut
accept the following arguments:
duration
- the time duration from complete silence to the signal's full amplitude (or the other way round for the case ofFadeOut
). Accepts milliseconds (float) or samples (int) as usual.curve
- the 'shape' of the fade, determining the exact nature of the shift from silence to full amplitude. Default islinear
, and see the Fade Curves page for the complete list and definitions.- Other, curve-specific arguments (see above link).
from gensound import test_wav, WAV, FadeIn, FadeOut
w = WAV(test_wav)[10e3:20e3]*FadeIn(duration=1e3)*FadeOut(duration=2e3)
w.play()
Crossfade
Cross-fade is used to seamlessly merge two bits of audio together.
Since this is a Transform that affects two Signals simultaneously, it uses a unique syntax: Signal | CrossFade | Signal
.
This will fade out the first Signal while fading in the second Signal.
It receives the same arguments as FadeIn
and FadeOut
.
Here, duration
indicates the total time where both signals overlap.
Thus, the resulting audio in the example below will only last 15 seconds.
from gensound import test_wav, WAV, CrossFade
w = WAV(test_wav)
s = w[10e3:20e3] | CrossFade(duration=5e3) | w[20.5e3:30.5e3]
s.play()
Note that the default curve for CrossFade
is polynomial
with degree=0.5
, which was chosen since it evens the loudness throughout the fade, though this may change if both Signals are highly correlated.
Time Dimension
Reverse
To play audio in reverse, apply the Reverse
transform. In the example code below, the L channel will be played in reverse, with the R channel remaining untouched:
w = WAV(test_wav)
w[0] *= Reverse()
w.play()
Extending Audio
To extend a signal by appending silence, apply the Extend
transform. It receives the single argument duration
, which, as usual, can accept either floats (milliseconds) or ints (number of samples).
The same effect can also be achieved by concatenating a Silence
Signal. These are incidentally the same, adding a second of silence at the end of the sine wave:
Sine() | Silence(1e3)
Sine()*Extend(1e3)
TODO what happens if we input a negative number? Currently would probably raise an error, but this can be taken to mean removing part of the signal. Although this is a useful action, this can also be done by Signal slicing, and also the name
Extend
wouldn't really fit any more.
Shifting Audio Around
To push Signals forward or backward in time, use the Shift
Transform. It receives the usual duration
argument, which indicates the amount of time by which to displace the Signal. Negative numbers will make the Signal appear earlier than expected. See the following examples, and note how this interacts with playback, concatenating and mixing:
w = WAV(test_wav)[10e3:15e3]
# add 2 seconds of silence at the beginning
(w*Shift(2e3)).play()
# mix two copies of the same signal, one delayed and played softer by adjusting the amplitude
(w + 0.5*w*Shift(1e3)).play()
# when concatenating two Signals, we can use negative Shift to create overlap:
(w | w*Shift(-2.5e3)).play() # 2.5 secs of overlap
# Haas effect, delaying L channel by a short period makes the sound appear to be coming from the right:
w[0] *= Shift(80) # shift by 80 samples
w.play() # use headphones for best effect
Trying to output a Signal which starts at a negative time will simply cause the playback or export to start from that specific time; so there will be no noticeable effect:
# playback will start at -2s as well, so there will be no noticeable effect
(w*Shift(-2e3)).play()
# if you want to cut the beginning of the Signal, just do this:
w[2e3:].play()