saysynth.core.font

The Font class creates a list of Notes within a scale and writes them to separate files. This makes them easy to import into samplers or DAWs.

 1"""
 2The Font class creates a list of `Notes` within a scale and writes them to separate files. This makes them easy to import into samplers or DAWs.
 3<center><img src="/assets/img/sun-wavy.png"></img></center>
 4"""
 5import os
 6from typing import Union
 7
 8from midi_utils import midi_scale, midi_to_note, note_to_midi
 9
10from .note import Note
11
12
13class Font(object):
14    def __init__(
15        self,
16        key: Union[str, int],
17        scale: str,
18        scale_start_at: Union[int, str],
19        scale_end_at: Union[int, str],
20        **note_options,
21    ):
22        """
23        The Font class creates a list of `Notes` within a
24        scale and writes them to separate files. This
25        makes them easy to import into samplers or DAWs.
26        Scale generation is provided by `midi_scale`
27        Args:
28            key: The root note of the scale, eg: C,D,G#,etc
29            scale: The name of the scale (see midi_utils.constants.SCALES)
30            scale_start_at: A note name or midi note number to start the scale at
31            scale_end_at: A note name or midi note number to end the scale at
32            **note_options: Additional options to pass to `Note` generation.
33        """
34        # add note type to simplify function call
35        self.scale = midi_scale(
36            key=key,
37            scale=scale,
38            min_note=note_to_midi(scale_start_at),
39            max_note=note_to_midi(scale_end_at),
40        )
41        note_options.setdefault("type", "note")
42        self.note_options = note_options
43
44    def _get_kwargs(self, midi, kwargs) -> dict:
45        kw = dict(self.note_options)
46        kw.update(kwargs)
47        kw["type"] = "note"
48        kw["midi"] = midi
49        kw["note"] = midi_to_note(midi)
50        return kw
51
52    def play(self, **kwargs) -> None:
53        """
54        Alias of `self.generate`
55        """
56        return self.generate(**kwargs)
57
58    def generate(self, **kwargs) -> None:
59        # generate files for each note in the scale
60        if not os.path.exists(kwargs["output_dir"]):
61            os.makedirs(kwargs["output_dir"], exist_ok=True)
62        for midi in self.scale:
63            kwargs = self._get_kwargs(midi, kwargs)
64
65            # generate audio output file name
66            filepath = (
67                f"{midi:03d}_{kwargs['note']}_"
68                f"{kwargs['voice'].lower()}_{kwargs['rate']}.{kwargs['format']}"
69            )
70            audio_output_file = os.path.join(
71                kwargs["output_dir"],
72                filepath,
73            )
74            # generate input file of text
75            note = Note(**kwargs)
76            note.play(
77                voice=kwargs["voice"],
78                rate=kwargs["rate"],
79                audio_output_file=audio_output_file,
80                wait=True,
81            )
82            if not os.path.exists(audio_output_file):
83                raise RuntimeError(
84                    f"File {audio_output_file} was not successfully created"
85                )
class Font:
14class Font(object):
15    def __init__(
16        self,
17        key: Union[str, int],
18        scale: str,
19        scale_start_at: Union[int, str],
20        scale_end_at: Union[int, str],
21        **note_options,
22    ):
23        """
24        The Font class creates a list of `Notes` within a
25        scale and writes them to separate files. This
26        makes them easy to import into samplers or DAWs.
27        Scale generation is provided by `midi_scale`
28        Args:
29            key: The root note of the scale, eg: C,D,G#,etc
30            scale: The name of the scale (see midi_utils.constants.SCALES)
31            scale_start_at: A note name or midi note number to start the scale at
32            scale_end_at: A note name or midi note number to end the scale at
33            **note_options: Additional options to pass to `Note` generation.
34        """
35        # add note type to simplify function call
36        self.scale = midi_scale(
37            key=key,
38            scale=scale,
39            min_note=note_to_midi(scale_start_at),
40            max_note=note_to_midi(scale_end_at),
41        )
42        note_options.setdefault("type", "note")
43        self.note_options = note_options
44
45    def _get_kwargs(self, midi, kwargs) -> dict:
46        kw = dict(self.note_options)
47        kw.update(kwargs)
48        kw["type"] = "note"
49        kw["midi"] = midi
50        kw["note"] = midi_to_note(midi)
51        return kw
52
53    def play(self, **kwargs) -> None:
54        """
55        Alias of `self.generate`
56        """
57        return self.generate(**kwargs)
58
59    def generate(self, **kwargs) -> None:
60        # generate files for each note in the scale
61        if not os.path.exists(kwargs["output_dir"]):
62            os.makedirs(kwargs["output_dir"], exist_ok=True)
63        for midi in self.scale:
64            kwargs = self._get_kwargs(midi, kwargs)
65
66            # generate audio output file name
67            filepath = (
68                f"{midi:03d}_{kwargs['note']}_"
69                f"{kwargs['voice'].lower()}_{kwargs['rate']}.{kwargs['format']}"
70            )
71            audio_output_file = os.path.join(
72                kwargs["output_dir"],
73                filepath,
74            )
75            # generate input file of text
76            note = Note(**kwargs)
77            note.play(
78                voice=kwargs["voice"],
79                rate=kwargs["rate"],
80                audio_output_file=audio_output_file,
81                wait=True,
82            )
83            if not os.path.exists(audio_output_file):
84                raise RuntimeError(
85                    f"File {audio_output_file} was not successfully created"
86                )
Font( key: Union[str, int], scale: str, scale_start_at: Union[int, str], scale_end_at: Union[int, str], **note_options)
15    def __init__(
16        self,
17        key: Union[str, int],
18        scale: str,
19        scale_start_at: Union[int, str],
20        scale_end_at: Union[int, str],
21        **note_options,
22    ):
23        """
24        The Font class creates a list of `Notes` within a
25        scale and writes them to separate files. This
26        makes them easy to import into samplers or DAWs.
27        Scale generation is provided by `midi_scale`
28        Args:
29            key: The root note of the scale, eg: C,D,G#,etc
30            scale: The name of the scale (see midi_utils.constants.SCALES)
31            scale_start_at: A note name or midi note number to start the scale at
32            scale_end_at: A note name or midi note number to end the scale at
33            **note_options: Additional options to pass to `Note` generation.
34        """
35        # add note type to simplify function call
36        self.scale = midi_scale(
37            key=key,
38            scale=scale,
39            min_note=note_to_midi(scale_start_at),
40            max_note=note_to_midi(scale_end_at),
41        )
42        note_options.setdefault("type", "note")
43        self.note_options = note_options

The Font class creates a list of Notes within a scale and writes them to separate files. This makes them easy to import into samplers or DAWs. Scale generation is provided by midi_scale

Arguments:
  • key: The root note of the scale, eg: C,D,G#,etc
  • scale: The name of the scale (see midi_utils.constants.SCALES)
  • scale_start_at: A note name or midi note number to start the scale at
  • scale_end_at: A note name or midi note number to end the scale at
  • **note_options: Additional options to pass to Note generation.
def play(self, **kwargs) -> None:
53    def play(self, **kwargs) -> None:
54        """
55        Alias of `self.generate`
56        """
57        return self.generate(**kwargs)

Alias of self.generate

def generate(self, **kwargs) -> None:
59    def generate(self, **kwargs) -> None:
60        # generate files for each note in the scale
61        if not os.path.exists(kwargs["output_dir"]):
62            os.makedirs(kwargs["output_dir"], exist_ok=True)
63        for midi in self.scale:
64            kwargs = self._get_kwargs(midi, kwargs)
65
66            # generate audio output file name
67            filepath = (
68                f"{midi:03d}_{kwargs['note']}_"
69                f"{kwargs['voice'].lower()}_{kwargs['rate']}.{kwargs['format']}"
70            )
71            audio_output_file = os.path.join(
72                kwargs["output_dir"],
73                filepath,
74            )
75            # generate input file of text
76            note = Note(**kwargs)
77            note.play(
78                voice=kwargs["voice"],
79                rate=kwargs["rate"],
80                audio_output_file=audio_output_file,
81                wait=True,
82            )
83            if not os.path.exists(audio_output_file):
84                raise RuntimeError(
85                    f"File {audio_output_file} was not successfully created"
86                )