Melody class#
This class is used for making/working with melodies..
- class thebeat.music.Melody(rhythm, pitch_names, octave=None, key=None, is_played=None, name=None)[source]#
A
Melody
object contains a both a rhythm and pitch information. It does not contain sound. However, theMelody
can be synthesized and played or written to disk, for instance using thesynthesize_and_play()
method.See the
__init__()
to learn how aMelody
object is constructed, or use one of the different class methods, such as thegenerate_random_melody()
method.Most of the functions require you to install abjad. Please note that the current version of abjad requires Python 3.10. The last version that supported Python 3.8-3.9 is this one. The correct version will be installed automatically when you install thebeat with
pip install thebeat[music_notation]
. For more details, see https://thebeat.readthedocs.io/en/latest/installation.html.- __init__(rhythm, pitch_names, octave=None, key=None, is_played=None, name=None)[source]#
- Parameters:
pitch_names (
ndarray
[Any
,dtype
[str
]] |list
[str
] |str
) – An array or list containing note names. They can be in a variety of formats, such as"G4"
for a G note in the fourth octave, or"g'"
, or simplyG
. The names are processed byabjad.pitch.NamedPitch
. Follow the link to find examples of the different formats. Alternatively it can be a string, but only in the formats:'CCGGC'
or'C4C4G4G4C4'
.key (
Optional
[str
], default:None
) – Optionally, you can provide a key. This is for instance used when plotting aMelody
object.is_played (
Optional
[list
], default:None
) – Optionally, you can indicate if you want rests in theMelody
. Provide an array or list of booleans, for instance:[True, True, False, True]
would mean a rest in place of the third event. The default is True for each event.name (
Optional
[str
], default:None
) – Optionally, theMelody
object can have a name. This is saved to theMelody.name
attribute.
Examples
>>> r = thebeat.music.Rhythm.from_note_values([4, 4, 4, 4, 4, 4, 2]) >>> mel = Melody(r, 'CCGGAAG')
- copy(deep=True)[source]#
Returns a copy of itself. See
copy.copy()
for more information.- Parameters:
deep (
bool
, default:True
) – IfTrue
, a deep copy is returned. IfFalse
, a shallow copy is returned.
- classmethod generate_random_melody(n_bars=1, beat_ms=500, time_signature=(4, 4), key='C', octave=4, n_rests=0, allowed_note_values=None, rng=None, name=None)[source]#
Generate a random rhythm as well as a melody, based on the given parameters. Internally, for the rhythm, the
Rhythm.generate_random_rhythm()
method is used. The melody is a random selection of pitch values based on the provided key and octave.- Parameters:
n_bars (
int
, default:1
) – The desired number of musical bars.beat_ms (
int
, default:500
) – The value (in milliseconds) for the beat, i.e. the duration of a \(\frac{1}{4}\) th note if the lower number in the time signature is 4.time_signature (
tuple
, default:(4, 4)
) – A musical time signature, for instance:(4, 4)
. As a reminder: the upper number indicates how many beats there are in a bar. The lower number indicates the denominator of the value that indicates one beat. So, in(4, 8)
time, a bar would be filled if we have four \(\frac{1}{8}\) th notes.key (
str
, default:'C'
) – The musical key used for randomly selecting the notes. Only major keys are supported for now.octave (
int
, default:4
) – The musical octave. The default is concert pitch, i.e.4
.n_rests (
int
, default:0
) – If desired, one can provide a number of rests to be inserted at random locations. These are placed after the random selection of note values.allowed_note_values (
list
, default:None
) – A list or array containing the denominators of the allowed note values. A note value of2
means a half note, a note value of4
means a quarternote etc. Defaults to[4, 8, 16]
.rng (
Generator
, default:None
) – Anumpy.random.Generator
object. If not suppliednumpy.random.default_rng()
is used.name (
Optional
[str
], default:None
) – If desired, one can give the melody a name. This is for instance used when printing the rhythm, or when plotting the rhythm. It can always be retrieved and changed viaRhythm.name
.
- Return type:
Examples
>>> generator = np.random.default_rng(seed=123) >>> m = Melody.generate_random_melody(rng=generator) >>> print(m.note_values) [16 16 16 16 16 16 16 8 8 16 8 16 16] >>> print(m.pitch_names) ["a'", "g'", "c'", "c''", "d'", "e'", "d'", "e'", "d'", "e'", "b'", "f'", "c''"]
- property note_values#
This property returns the denominators of the note values in this sequence, calculated from the inter-onset intervals (IOIs). A note value of
2
means a half note. A note value of4
means a quarternote, etc. One triplet of three notes would be[12, 12, 12]
.Caution
Please note that this function is basic (e.g. there is no support for dotted notes etc.). That’s beyond the scope of this package.
Examples
>>> r = thebeat.music.Rhythm([500, 1000, 250, 250], time_signature=(4, 4), beat_ms=500) >>> m = Melody(r, pitch_names='CCGC') >>> print(r.note_values) [4 2 8 8]
>>> r = thebeat.music.Rhythm([166.66666667, 166.66666667, 166.66666667, 500, 500, 500], beat_ms=500] >>> print(r.note_values) [12 12 12 4 4 4]
- plot_melody(filepath=None, key=None, suppress_display=False, figsize=None, dpi=600)[source]#
Use this function to plot the melody in musical notes. It requires lilypond to be installed. See
Rhythm.plot_rhythm()
for installation instructions.- Parameters:
filepath (
UnionType
[PathLike
,str
,None
], default:None
) – Optionally, you can save the plot to a file. Supported file formats are only ‘.png’ and ‘.eps’. The desired file format will be selected based on what the filepath ends with.key (
Optional
[str
], default:None
) – The musical key to plot in. Can differ from the key used to construct theMelody
object. Say you want to emphasize the accidentals (sharp or flat note), you can choose to plot the melody in ‘C’. The default is to plot in the key that was used to construct the object.suppress_display (
bool
, default:False
) – If desired,you can choose to suppress displaying the plot in your IDE. This means thatmatplotlib.pyplot.show()
is not called. This is useful when you just want to save the plot or use the returnedmatplotlib.figure.Figure
andmatplotlib.axes.Axes
objects.figsize (
Optional
[tuple
[float
,float
]], default:None
) – The figure size in inches, as a tuple of floats. This refers to the figsize argument inmatplotlib.pyplot.figure()
.dpi (
int
, default:600
) – The resolution of the plot in dots per inch.
- Return type:
Examples
>>> r = thebeat.music.Rhythm(iois=[250, 500, 250, 500], time_signature=(3, 4)) >>> m = Melody(r, 'CCGC') >>> m.plot_melody()
>>> m.plot_melody(filepath='mymelody.png', suppress_display=True)
>>> fig, ax = m.plot_melody(key='C', suppress_display=True)
- synthesize_and_play(event_durations_ms=None, fs=48000, n_channels=1, amplitude=1.0, oscillator='sine', onramp_ms=0, offramp_ms=0, ramp_type='linear', metronome=False, metronome_amplitude=1.0)[source]#
Since
Melody
objects do not contain any sound information, you can use this method to first synthesize the sound, and subsequently have it played via the internally usedsounddevice.play()
.Note
Theoretically, four quarternotes played after each other constitute one long sound. This behaviour is the default here. However, in many cases it will probably be best to supply
event_durations
, which means the events are played in the rhythm of the melody (i.e. according to the inter-onset intervals of the rhythm), but using a supplied duration.- Parameters:
event_durations_ms (
UnionType
[list
[int
],ndarray
[Any
,dtype
[int
]],int
,None
], default:None
) – Can be supplied as a single integer, which means that duration will be used for all events in the melody, or as an array of list containing individual durations for each event. That of course requires an array or list with a size equal to the number of notes in the melody.fs (
int
, default:48000
) – The desired sampling frequency in hertz.n_channels (
int
, default:1
) – The desired number of channels. Can be 1 (mono) or 2 (stereo).amplitude (
float
, default:1.0
) – Factor with which sound is amplified. Values between 0 and 1 result in sounds that are less loud, values higher than 1 in louder sounds. Defaults to 1.0.oscillator (
str
, default:'sine'
) – The oscillator used for generating the sound. Either ‘sine’ (the default), ‘square’ or ‘sawtooth’.onramp_ms (
int
, default:0
) – The sound’s ‘attack’ in milliseconds.offramp_ms (
int
, default:0
) – The sound’s ‘decay’ in milliseconds.ramp_type (
str
, default:'linear'
) – The type of on- and offramp used. Either ‘linear’ (the default) or ‘raised-cosine’.metronome (
bool
, default:False
) – IfTrue
, a metronome sound is added for playback. It usesMelody.beat_ms
as the inter-onset interval.metronome_amplitude (
float
, default:1.0
) – If desired, when writing the object with a metronome sound you can adjust the metronome amplitude. A value between 0 and 1 means a less loud metronome, a value larger than 1 means a louder metronome sound.
Examples
>>> mel = Melody.generate_random_melody() >>> mel.synthesize_and_play()
>>> mel.synthesize_and_play(event_durations_ms=50)
- synthesize_and_return(event_durations_ms=None, fs=48000, n_channels=1, amplitude=1.0, oscillator='sine', onramp_ms=0, offramp_ms=0, ramp_type='linear', metronome=False, metronome_amplitude=1.0)[source]#
Since
Melody
objects do not contain any sound information, you can use this method to synthesize the sound. It returnes a tuple containing the sound samples as a NumPy 1-D array, and the sampling frequency.Note
Theoretically, four quarternotes played after each other constitute one long sound. This behaviour is the default here. However, in many cases it will probably be best to supply
event_durations
, which means the events are played in the rhythm of the melody (i.e. according to the inter-onset intervals of the rhythm), but using a supplied duration.- Parameters:
event_durations_ms (
UnionType
[list
[int
],ndarray
[Any
,dtype
[int
]],int
,None
], default:None
) – Can be supplied as a single integer, which means that duration will be used for all events in the melody, or as an array of list containing individual durations for each event. That of course requires an array or list with a size equal to the number of notes in the melody.fs (
int
, default:48000
) – The desired sampling frequency in hertz.n_channels (
int
, default:1
) – The desired number of channels. Can be 1 (mono) or 2 (stereo).amplitude (
float
, default:1.0
) – Factor with which sound is amplified. Values between 0 and 1 result in sounds that are less loud, values higher than 1 in louder sounds. Defaults to 1.0.oscillator (
str
, default:'sine'
) – The oscillator used for generating the sound. Either ‘sine’ (the default), ‘square’ or ‘sawtooth’.onramp_ms (
int
, default:0
) – The sound’s ‘attack’ in milliseconds.offramp_ms (
int
, default:0
) – The sound’s ‘decay’ in milliseconds.ramp_type (
str
, default:'linear'
) – The type of on- and offramp_ms used. Either ‘linear’ (the default) or ‘raised-cosine’.metronome (
bool
, default:False
) – IfTrue
, a metronome sound is added to the samples. It usesMelody.beat_ms
as the inter-onset interval.metronome_amplitude (
float
, default:1.0
) – If desired, when synthesizing the object with a metronome sound you can adjust the metronome amplitude. A value between 0 and 1 means a less loud metronome, a value larger than 1 means a louder metronome sound.
- Return type:
Examples
>>> mel = Melody.generate_random_melody() >>> samples, fs = mel.synthesize_and_return()
- synthesize_and_write(filepath, event_durations_ms=None, fs=48000, n_channels=1, amplitude=1.0, dtype=<class 'numpy.int16'>, oscillator='sine', onramp_ms=0, offramp_ms=0, ramp_type='linear', metronome=False, metronome_amplitude=1.0)[source]#
Since
Melody
objects do not contain any sound information, you can use this method to first synthesize the sound, and subsequently write it to disk as a wave file.Note
Theoretically, four quarternotes played after each other constitute one long sound. This behaviour is the default here. However, in many cases it will probably be best to supply
event_durations
, which means the events are played in the rhythm of the melody (i.e. according to the inter-onset intervals of the rhythm), but using a supplied duration.- Parameters:
filepath (
str
|PathLike
) – The output destination for the .wav file. Either pass e.g. aPath
object, or a string. Of course be aware of OS-specific filepath conventions.event_durations_ms (
UnionType
[list
[int
],ndarray
[Any
,dtype
[int
]],int
,None
], default:None
) – Can be supplied as a single integer, which means that duration will be used for all events in the melody, or as an array of list containing individual durations for each event. That of course requires an array or list with a size equal to the number of notes in the melody.fs (
int
, default:48000
) – The desired sampling frequency in hertz.n_channels (
int
, default:1
) – The desired number of channels. Can be 1 (mono) or 2 (stereo).amplitude (
float
, default:1.0
) – Factor with which sound is amplified. Values between 0 and 1 result in sounds that are less loud, values higher than 1 in louder sounds. Defaults to 1.0.dtype (
str
|dtype
, default:<class 'numpy.int16'>
) – The desired data type for the output file. Defaults tonp.int16
. This means that the output file will be 16-bit PCM.oscillator (
str
, default:'sine'
) – The oscillator used for generating the sound. Either ‘sine’ (the default), ‘square’ or ‘sawtooth’.onramp_ms (
int
, default:0
) – The sound’s ‘attack’ in milliseconds.offramp_ms (
int
, default:0
) – The sound’s ‘decay’ in milliseconds.ramp_type (
str
, default:'linear'
) – The type of on- and offramp used. Either ‘linear’ (the default) or ‘raised-cosine’.metronome (
bool
, default:False
) – IfTrue
, a metronome sound is added to the output file. It usesMelody.beat_ms
as the inter-onset interval.metronome_amplitude (
float
, default:1.0
) – If desired, when playing the object with a metronome sound you can adjust the metronome amplitude. A value between 0 and 1 means a less loud metronome, a value larger than 1 means a louder metronome sound.
Examples
>>> mel = Melody.generate_random_melody() >>> mel.synthesize_and_write(filepath='random_melody.wav')