Scores - davidpanderson/Numula GitHub Wiki
The nscore
module lets you create data structures representing musical scores.
from numula.nscore import *
Note
class Represents a note, with a specified start time, duration, pitch, and volume.
Note(
time: float,
dur: float,
pitch: int,
vol: float,
tags: list[str]=[]
)
Creates a Note
object. Parameters:
time
: The note's start time in "score units" in which 1 is the duration of a 4/4 measure; i.e. a 'beat' is 0.25 score units. The default tempo is 60 beats per minute.dur
: The note's duration (i.e. the amount of time it sounds) in score units.pitch
: The note's pitch in the MIDI scale (0..127, 60 = middle C).vol
: The note's volume, 0..1tags
: An optional list of text "tags"; these and other note attributes can be used used by nuance functions to select groups of notes.
If you're entering a score,
you typically don't create Note
objects directly.
Instead, use a shorthand notation that
creates them for you.
Score
class Represents a set of notes, pedal applications, and measures.
Score(tempo: float=60)
Creates a Score
.
tempo
is in beats per minute.
To vary the tempo within the piece,
use the timing control functions.
Score.insert_note(note: Note)
Add the given note to the score.
Score.write_midi(filename: str)
Generate a MIDI file for the score.
We can now create some music:
import random
ns = Score()
for i in range(200):
time = random.uniform(0, 10)
dur = random.uniform(.1, 1)
pitch = random.randrange(40, 80)
vol = random.uniform(.1, .8)
ns.insert_note(Note(time, dur, pitch, vol))
ns.write_midi("random.midi")
This plays 200 notes randomly spaced over 40 seconds (10 4-beat measures at quarter=60), with random duration, pitch, and volume.
Other members of Score
:
Score.append_note(note: Note)
A Score
has a "current time", initially zero.
append_note()
adds a note starting at that time.
It doesn't change the current time.
Score.advance_time(dt: float)
Add dt
to the current time.
dt
may be positive or negative.
Score.insert_score(score: Score, t: float=0, tag: str='')
Merge another Score
into this one, starting at time t
.
The other score's notes, pedals, and measure boundaries
are added to this Score
,
with t
added to their start times.
If tag
is specified, tag the added notes.
Score.append_score(score: Score, tag='')
Append the given Score
to this one.
If tag
is specified, tag the added notes.
Score.append_scores(scores: list[Score], tag='')
Insert the given scores into this Score
,
starting at the current time.
Then advance the current time by the duration of the longest Score
.
Score.tag(tag: str)
Add the given tag to all notes in the score.
Score.trim(t0: float, t1: float)
Trim the score to the time range [t0...t1].
print(ns)
prints the score's notes,pedals, and measure boundaries in human-readable form.
Measure
class Represents a measure (i.e. a metric unit).
Measure(t, dur: float, type: str)
t
: start time of the measuredur
: duration of the measuretype
: a string of your choosing describing the metric structure of the measure.
For example:
Measure(0., '2+2+3/8')
could represent a measure of 2+2+3 eighth notes, starting at time 0.
Score.insert_measure(m: Measure)
Add a Measure
object to a Score
.
Score.append_measure(duration: float, type: str)
Append a measure of the given duration and type to a Score
.
Measures are optional. They provide a framework for nuance based on position in the measure. For example, if you've added Measures to a score you can do things like:
Score.vol_adjust(0.9, lambda n: n.measure_type=='4/4' and n.measure_offset in [1, 2, 3])
Score.vol_adjust(0.8, lambda n: n.measure_type=='4/4' and n.measure_offset not in [0, 1, 2, 3])
attenuates the volume of notes in 4/4 measures based on their position:
- The downbeat is not attenuated
- The 2nd, 3rd, and 4th beats are attenuated by .9
- Other notes are attenuated by .8