Skip to content

Commit 31802a1

Browse files
committed
Add MusicComposition dataclass and play_composition method
1 parent db8bef1 commit 31802a1

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

src/arduino/app_bricks/sound_generator/__init__.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from .generator import WaveSamplesBuilder
1616
from .effects import *
1717
from .loaders import ABCNotationLoader
18+
from .composition import MusicComposition as MusicComposition
1819

1920
logger = Logger("SoundGenerator", logging.DEBUG)
2021

@@ -591,6 +592,39 @@ def play_polyphonic(self, notes: list[list[tuple[str, float]]], as_tone: bool =
591592
if block and duration > 0.0:
592593
time.sleep(duration)
593594

595+
def play_composition(self, composition: "MusicComposition", block: bool = False):
596+
"""
597+
Play a MusicComposition object.
598+
599+
This method configures the SoundGenerator with the composition's settings
600+
and plays the polyphonic sequence.
601+
602+
Args:
603+
composition (MusicComposition): The composition to play.
604+
block (bool): If True, block until the entire composition has been played.
605+
606+
Example:
607+
```python
608+
from arduino.app_bricks.sound_generator import MusicComposition, SoundGenerator, SoundEffect
609+
610+
comp = MusicComposition(
611+
composition=[[("C4", 0.25), ("E4", 0.25)], [("G4", 0.5)]], bpm=120, waveform="square", volume=0.8, effects=[SoundEffect.adsr()]
612+
)
613+
614+
gen = SoundGenerator()
615+
gen.start()
616+
gen.play_composition(comp, block=True)
617+
```
618+
"""
619+
# Configure the generator with composition settings
620+
self.set_bpm(composition.bpm)
621+
self.set_wave_form(composition.waveform)
622+
self.set_master_volume(composition.volume)
623+
self.set_effects(composition.effects)
624+
625+
# Play the composition
626+
self.play_polyphonic(composition.composition, volume=composition.volume, block=block)
627+
594628
def play_chord(self, notes: list[str], note_duration: float | str = 1 / 4, volume: float = None, block: bool = False):
595629
"""
596630
Play a chord consisting of multiple musical notes simultaneously for a specified duration and volume.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc)
2+
#
3+
# SPDX-License-Identifier: MPL-2.0
4+
5+
from dataclasses import dataclass, field
6+
from .effects import SoundEffect
7+
8+
9+
@dataclass
10+
class MusicComposition:
11+
"""
12+
A structured representation of a musical composition for SoundGenerator.
13+
14+
This class encapsulates all the parameters needed to play a polyphonic composition,
15+
making it easy to save, load, and share musical sequences.
16+
17+
Attributes:
18+
composition (list[list[tuple[str, float]]]): Polyphonic sequence as a list of tracks.
19+
Each track is a list of tuples (note, duration).
20+
Duration is in note fractions (1/4 = quarter note, 1/8 = eighth note).
21+
Example: [[("C4", 0.25), ("E4", 0.25)], [("G4", 0.5)]]
22+
bpm (int): Tempo in beats per minute. Default: 120.
23+
waveform (str): Wave form type ("sine", "square", "triangle", "sawtooth"). Default: "sine".
24+
volume (float): Master volume level (0.0 to 1.0). Default: 0.8.
25+
effects (list): List of SoundEffect instances to apply. Default: [SoundEffect.adsr()].
26+
27+
Example:
28+
```python
29+
from arduino.app_bricks.sound_generator import MusicComposition, SoundGenerator, SoundEffect
30+
31+
# Create a composition
32+
comp = MusicComposition(
33+
composition=[
34+
[("C4", 0.25), ("E4", 0.25), ("G4", 0.25)], # Track 1
35+
[("REST", 0.25), ("C5", 0.5)], # Track 2
36+
],
37+
bpm=120,
38+
waveform="square",
39+
volume=0.8,
40+
effects=[SoundEffect.adsr(), SoundEffect.tremolo(depth=0.5, rate=5.0)],
41+
)
42+
43+
# Configure and play with SoundGenerator
44+
gen = SoundGenerator()
45+
gen.start()
46+
gen.play_composition(comp, block=True)
47+
48+
# Alternatively, set parameters manually and play
49+
gen = SoundGenerator()
50+
gen.start()
51+
gen.set_bpm(comp.bpm)
52+
gen.set_wave_form(comp.waveform)
53+
gen.set_master_volume(comp.volume)
54+
gen.set_effects(comp.effects)
55+
gen.play_polyphonic(comp.composition, volume=comp.volume, block=True)
56+
```
57+
"""
58+
59+
composition: list[list[tuple[str, float]]]
60+
bpm: int = 120
61+
waveform: str = "sine"
62+
volume: float = 0.8
63+
effects: list = field(default_factory=lambda: [SoundEffect.adsr()])

0 commit comments

Comments
 (0)