xnano.music
xnano.music
¶
xnano.music
Notes and sound: note makes a Note you can define anywhere, and
play plays notes, sounds and melodies on the running canvas or on this
computer's sound output. Playing needs the optional audio extra:
pip install "xnano[audio]".
Classes:
-
Note–A note, or a chord, to play: a pitch, how long it lasts and how it sounds.
-
PlayHandle–What
playreturns: tells whether the sound is over and can cut it short.
Functions:
-
note–Make a
Note: a pitch, or several for a chord, with its length and sound. -
play–Play a note, a sound, a symbol name, a melody or a sequence of those.
Note
dataclass
¶
Note(pitch: Pitch | tuple[Pitch, ...], beats: float = 1.0, instrument: InstrumentName = 'piano', velocity: float = 0.8, effects: tuple[PlayableEffectSpecification, ...] = (), symbol: str | None = None)
A note, or a chord, to play: a pitch, how long it lasts and how it sounds.
A note is a plain value. It needs no sound device, no canvas and not even the audio
extra to be created, so a song can be defined at the top of a module and played later
with play or Canvas.play. A sequence of
notes plays one after another. symbol registers the note under a name, so
play('kick') finds it.
Attributes:
-
pitch(Pitch | tuple[Pitch, ...]) –A note name such as
'C#4', a MIDI number from 0 to 127 (60 is middle C), or a tuple of them for a chord. -
beats(float) –How long the note is held, in beats at the canvas's tempo. A beat is half a second at 120 beats per minute.
-
instrument(InstrumentName) –A built-in instrument, from
instrument_names. -
velocity(float) –How hard the note is played, from 0.0 to 1.0.
-
effects(tuple[PlayableEffectSpecification, ...]) –Sound effects as dictionaries with a
kindkey, such as{'kind': 'audio.reverb', 'mix': 0.4}. -
symbol(str | None) –The name the note is registered under in
symbols, orNone.
Raises:
-
TypeError–The pitch is not a note name or a number, or an effect is not a dictionary.
-
ValueError–The pitch is not valid,
beatsis not above 0,velocityis not from 0.0 to 1.0, or the instrument is unknown (checked when theaudioextra is installed, and otherwise when the note is played).
Examples:
import xnano
chord = xnano.Note(('C4', 'E4', 'G4'), beats=2.0, instrument='bell')
assert chord.beats == 2.0
with xnano.new(width=8, height=1) as canvas:
canvas.play([chord, xnano.note('C5')])
canvas.step(delta_seconds=1.0)
assert canvas.audio.render_sound().duration_milliseconds == 1000.0
Methods:
-
__post_init__–Check the values and register the symbol.
-
__xnano_play__–Return this note, so a note is playable like any other component.
pitch
instance-attribute
¶
A note name, a MIDI number, or a tuple of them for a chord.
instrument
class-attribute
instance-attribute
¶
instrument: InstrumentName = 'piano'
The built-in instrument.
velocity
class-attribute
instance-attribute
¶
velocity: float = 0.8
How hard the note is played, from 0.0 to 1.0.
effects
class-attribute
instance-attribute
¶
effects: tuple[PlayableEffectSpecification, ...] = ()
The sound effects, as dictionaries with a kind key.
symbol
class-attribute
instance-attribute
¶
symbol: str | None = None
The registered symbol name, or None.
__post_init__
¶
Check the values and register the symbol.
Source code in xnano/music.py
__xnano_play__
¶
PlayHandle
¶
PlayHandle(*, clock: Callable[[], float], end_seconds: float, cancel: Callable[[], None] | None = None)
What play returns: tells whether the sound is over and can cut it short.
Attributes:
-
is_finished(bool) –Whether the sound has ended or the handle was removed. On a canvas from
newthis follows the canvas's clock; on a device it follows the real time since the sound was handed over.
Examples:
import xnano
with xnano.new(width=8, height=1) as canvas:
handle = canvas.play(xnano.note('C4', beats=1.0))
assert not handle.is_finished
handle.remove()
assert handle.is_finished
Make a handle. Use the handle that play returns instead of calling this.
Parameters:
-
clock(Callable[[], float]) –Returns the current time in seconds.
-
end_seconds(float) –The time on that clock at which the sound is over.
-
cancel(Callable[[], None] | None, default:None) –Called once by
remove().
Methods:
-
remove–Stop the sound from playing any further, as far as it has not been heard yet.
Source code in xnano/music.py
remove
¶
Stop the sound from playing any further, as far as it has not been heard yet.
On a canvas from new the part that has not been rendered by
render_sound is dropped. On a device a sound
that was already handed to the output plays to its end, and one still waiting for its
beat never starts. Removing twice does nothing.
Source code in xnano/music.py
note
¶
note(pitch: Pitch | Sequence[Pitch], *, beats: float = 1.0, instrument: InstrumentName = 'piano', velocity: float = 0.8, effects: Sequence[PlayableEffectSpecification] = (), symbol: str | None = None) -> Note
Make a Note: a pitch, or several for a chord, with its length and sound.
Nothing is played and no sound device is needed. Play it with play or
Canvas.play. symbol='kick' registers the note, and then
play('kick') plays it.
Parameters:
-
pitch(Pitch | Sequence[Pitch]) –A note name such as
'C#4', a MIDI number from 0 to 127, or a sequence of them for a chord. -
beats(float, default:1.0) –How long the note is held, in beats.
-
instrument(InstrumentName, default:'piano') –A built-in instrument, from
instrument_names. -
velocity(float, default:0.8) –How hard the note is played, from 0.0 to 1.0.
-
effects(Sequence[PlayableEffectSpecification], default:()) –Sound effects as dictionaries with a
kindkey, such as{'kind': 'audio.reverb'}. -
symbol(str | None, default:None) –
Raises:
-
TypeError–The pitch is not a note name or a number.
-
ValueError–A value is out of range or the instrument is unknown.
Examples:
import xnano
kick = xnano.note('C2', instrument='kick', symbol='kick_drum')
with xnano.new(width=8, height=1) as canvas:
canvas.play('kick_drum')
canvas.step(delta_seconds=0.5)
assert canvas.audio.render_sound().peak > 0.0
Source code in xnano/music.py
play
¶
play(playable: PlaySource, /, **options: Unpack[PlayOptions]) -> PlayHandle
Play a note, a sound, a symbol name, a melody or a sequence of those.
The sound goes to the running canvas (see active); with no canvas
running it goes to this computer's sound output. On a canvas from new,
which has a clock you move, the sound is recorded and makes no noise: read it with
canvas.audio.render_sound().
A str is a symbol name first, so play('kick') plays the note or sound registered
with symbol='kick'. Any other str is a note name such as 'C#4', a frequency such
as '440hz' or melody text: notes separated by spaces, :2 holds a note for two
beats, rest is a silence, + joins a chord and | marks a bar, as in
'C4 E4 G4:2 rest C5+E5+G5'. A sequence plays one after another. An option replaces
the same value on a Note, so play(note('C4'), instrument='violin')
plays the violin.
Parameters:
-
playable(PlaySource) –What to play.
-
**options(Unpack[PlayOptions], default:{}) –See
PlayOptions:instrument,velocity,effects,volume,pan,at_beatandbeats, the length in beats of a note name, a number or aNote.
Returns:
-
PlayHandle–A
PlayHandle.
Raises:
-
ImportError–xnano-audiois not installed. Install it withpip install "xnano[audio]". -
TerminalAudioUnavailableError–No canvas is running and this computer has no sound output device.
-
ValueError–An option is out of range, or a
stris neither a symbol, a note name nor melody text. The message lists the known sound symbols.
Examples:
import xnano
with xnano.new(width=8, height=1) as canvas:
xnano.play([xnano.note('C4'), xnano.note('E4'), xnano.note('G4')])
canvas.step(delta_seconds=1.5)
assert canvas.audio.render_sound().peak > 0.0