Package: saysynth
MakemusicwithMac'ssaycommand.saysynthonly works with Mac OS X versions 12.X and below!!!🔊Demossaysynthsounds like this:<iframe width="100%" height="300" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/playlists/1519081741&color=%23ff5500&auto_play=true&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true"></iframe>brian abelson·saysynth demos v1.0.0You can also purchase recordings of these demos onbandcamp.Artwork byJeremiah McNair.🙋Aboutsaysynthis a a synthesizer built on top of Apple's built-inSpeech Synthesisframework, first introduced nearly 30 years ago,when Steve Jobs demoed "Fred".saysynthprovides utilities for synthesizing notes, chords, arpeggiated melodies, multi-track sequences and more!☞ how it worksAt some point in Fred's development, Apple decided they needed to give developers the ability to control the pitch and speaking rate of his voice. These capabilities were provided via adomain-specific language(DSL) Apple created to allow users to control the duration and pitch contours of individualphonemes. Eventually, this DSL was expanded to support "Alex" and "Victoria", two other built-in voices. The syntax for this DSL looks like this:AA {D 120; P 176.9:0 171.4:22 161.7:61}WhereAAis avalid phoneme,D 120is the duration of the phoneme in milliseconds, andP 176.9:0 171.4:22 161.7:61represents the pitch contour for the phoneme in colon-separated pairs of frequency and percentage duration.saysynthworks by harnessing this DSL to create musical passages with thesaycommand, mapping notes onto their associated frequencies viamidi-utils, generating phonemes with pitch contours (as described inApple's Speech Synthesis Programming Guide), and spawning multiple subprocesses in Python to create polyphonic, mostly drone-oriented music. Rudimentary text-to-speech capabilities are provided byg2p-en, a library for extracting phonemes from words, though, as of now, some trial and error is necessary to get this sounding intelligible. You can read more about my motivation in building this toolhere.🛠️Installationsaysynthonly works on Mac OS X machines with a workingsayinstallation. By default, the path to the executable is set to/usr/bin/say. You can override that path by setting the environment variableSAYSYNTH_SAY_EXECUTABLE.☞ via pypiFirst, installpythonviahomebrew(eg:brew install python)Next, run:pipinstall--user--upgradesaysynthYou should now be able to runsy --help. This command will also update a currently-installed instance ofsaysynth.💻Command-Line Interface (sy)saysynthis primarily designed to be used via it's command-line interface (syfor short).You can view all commands (and their corresponding docs) by runningssy --help:Usage:sy[OPTIONS]COMMAND[ARGS]...Makemusicwiththe`say`command.

Options:--helpShowthismessageandexit.

Commands:chordGenerateapolyphonicchord.versionPrintthecurrentversionofsaysynthtotheconsole.listListallcurrentlyrunningsaysynthprocesses.midiSynthesizeamelodyfromafully-monophonicmidifile.stopStopcurrentlyrunning`say`processesby`sequence`,`track`,...fontGivenascaleandotherparameters,generateasoundfontof...arpGenerateanarpeggiatedmelody.demoPlayabuilt-indemo.noteGenerateanindividualnote.seqPlayasequenceof`chord`,`midi`,`note`,and/or`arp`...Below are basic details on each command's functionality.☞ sy notesy noteaccepts a note name (eg:C3) or midi note number (eg:69) and generates input to thesaycommand which makes a monophonic note.examplesPlay the noteD#2randomizing the phoneme each segment by choosing from thedrone-like phonemes forFreds voice.synote'D#2'--randomize-phoneme'Fred:drone'--randomize-segments'phoneme'You can see the full list of options for this command viasy note --help.☞ sy arpsy arpaccepts a chord root (eg:C3), chord name, and list of styles to generate a melodic, arpeggiated sequence of speech synthesis.examplePlay an acid-like sequence:syarp'E0'`# set the root of the arpeggiator to E-1` \--chord-notes'0,3,5,7,9,12,14,25,31'`# set the notes of the arpeggiator` \--text'. TEE BEE THREE OH THREE  .'`# text to sing` \--styles'down,random_shuffle,random_octaves'`# arpeggiator style names come from the midi-utils module.` \--beat-bpm'130'`# the bpm to use when applying the note-count ` \--beat-count'1/32'`# the duration of each beat in the arpeggiator` \--note-bpm'130'`# the bpm to use when applying the note-count` \--note-count'1/32'`# the duration of each note` \--segment-bpm'130'`# the bpm to use when applying the segment-count` \--segment-count'1/32'`# the duration of each phoneme segment` \--velocities'60,90,127'`# a list of velocities to apply in order to the outputted notes` \--duration'15000'`# the total duration of the arpeggiator in milliseconds` \--render-volume-level-per-note'5'`# see docs` \--render-volume-level-per-segment'5'`# see docs`You can see the full list of options for this command viasy arp --help.☞ sy chordsy chordaccepts a chord root (eg:C3) or midi note number (eg:69), a chord name (eg: min6), and other parameters to spawn multiplesaycommands that generate a polyphonic chord.examplePlay a slowly-evolving minor 6th chord:sychord'C2'`# the root of the chord` \--chord'min6'`# the name of the chord which comes from midi-utils` \--duration'45000'`# the duration in ms` \--segment-bpm'155'`# the bpm to use when using --segment-count` \--segment-count'1/16'`# the duration of each segment in the note` \--attack'0.5'--decay'0'--sustain'0.5'--release'0.5'`# ADSR settings` \--randomize-segments'phoneme'`# phoneme-level randomization settings` \--voice'Alex'`# the voice to use, either Fred, Victoria, or Alex` \--phoneme'm,OW,EW'`# list of phonemes to randomly pick from` \--volume-range0.030.33`# min and mix of volume range`You can see the full list of options for this command viasy chord --help.☞ sy fontsy fontenables the generation of"soundfonts"or directories of individual sound files, which can be used in a sampler or DAW to create custom instruments. All synthesis parameters fromsy notecan be modified insy font.exampleCreate a directory of audio files, one per pitch in a specified scale. These can be used to create instruments in a DAW / livecoding environment of your choice:mkdir-ptmp`# create an output directory`syfont\--scale-start-at'C2'`# the lowest note of the scale to generate` \--scale-end-at'C5'`# the highest note of the scale to generate` \--key'C'`# the key of the --scale` \--scale'octatonic_whole'`# the scale to use when selecting the notes to generate. (from midi_utils)` \--output-dir'tmp/'`# the directory to write each file to` \--format'aiff'`# the format of each file` \--duration'1000'`# the duration of each file`You can see the full list of options for this command viasy font --help.☞ sy midisy midiaccepts a midi file and generates pitched phonemes. The midi files must be fully monophonic. (In other words there must not be any overlapping notes. Eventually I'll figure out this issue, but for now there is a helpful error message which indicates the name of an overlapping note and the time at which it occurs. You can then use this information to edit your midi file in whatever DAW you use. There is also no support for multi-track midi files, though that will be less challenging to implement.)sy midithen maps the notes in the midi file onto pitched phonemesexampleTo run this example, clone this repository and execute the following command from the root directory. Alternatively, generate your own midi file and replace it's path withexamples/arp.mid.Play a high-pitched sequence from a a midi file.symidi'examples/arp.mid'--phoneme'm'You can see the full list of options for this command viasy midi --help.☞ sy seqsy seqaccepts ayamlfilepath specifying multiplesaysynthcommands to be concurrently executed.Theyamlfile might look something like this:name:my-sequence# The name of the sequence. You pass sequence names into `sy stop` or `sy seq stop` to stop all tracks in a sequence at once.globals:# Configurations shared between all tracksduration_bpm:80# The bpm to use when calculating each tracks durationduration_count:128# The beat count to use when calculating each tracks durationtracks:# List of tracks / configurationschord1:# The name of the track. You can use track names to dynamically start/stop each track via the -t flag.type:chord# The type of this track. Either chord, arp, note, or midi.options:# Options to pass to the `chord` function.#   These can also be the shortened versions (eg. 'c' instead of 'chord')root:E3# The root note of the chordchord:min6# The name of the chordsegment_bpm:80# The bpm to use when calculating the length of each segmentphoneme:'m,2OW'note1:type:noteoptions:phoneme:'m,2OW'start_bpm:80# The bpm to use when calculating the start timestart_count:4# Delay the start of this track by a count of 4duration_count:124# Make the duration of this track shorter than the global setting by a count of 4note:F#3# The note to synthesize.Whereglobalsdefine options shared between alltracks, each of which have atypewhich corresponds to asaysynthcommand (chord,midi,note, and/orarp) and a set ofoptions.All commands can also generate ayamlversion of its parameters by appending the--yamloption. For instancesy note E#3 -rp Fred:note --yamlwould generate something like this:tracks:-note-b2lw2:type:noteoptions:root:64randomize_phoneme:Fred:notesubcommandssy seqprovides multiple subcommands to control the behavior of your sequence. These include:play: Play the sequence as-is, from beginning to end, respecting anystart_*configurations.start: Launch all tracks in the sequence immediately, irregardless of anystart_*configurations.stop: Stop one or more tracks currently playing from the sequence.echo: Print the sequence to the console.render: Render all tracks in the sequence as separate, monophonic audio-files.Each of these subcommands accepts command line flags, as well. For instance,--tracksallows you toplay,start,stop, orrenderonly certain tracks in the sequence. Similarly--audio-devicesallows
you to filter tracks which are configured to play on certain audio outputs.--config-overridesprovides the ability to override global and track-level configurations at runtime by passing in yaml-formatted configurations, eg:-c '{"foo":"bar"}'. These configurations can be specified at the track-level by nesting them under the track name, eg:-c '{"track":{"foo":"bar"}}'.You can also override configurations by providing extra command line arguments available tomidi,note,chord, rand/orarptracks, eg:-sd 10or--segment- duration 10. These can be similarly nested by using a__separator, eg:--track__segment-duration 10. Parameters specified via the --config-overrides option will take precedence over any extra CLI arguments.Finally,--output-dirallows you to specify the directory to write audio files into as a part of therendercommand.exampleTo run this example, clone this repository and execute the following command from the root directory. Alternatively, generate your ownyamlfile and replace it's path withexamples/hello-world.yml.Launch a multi-track sequence from ayamlfile and stop it after 10 seconds:syseqplayexamples/hello-world.yml
sleep10syseqstopexamples/hello-world.yml-thello_worldYou can also see an archive of my pastsaysynthperformancesfor examples of sequences.You can see the full list of options for this command viasy seq --help.☞ sy stopsy stopallows you to stop currently runningsaysynthprocesses bysequences,tracks,audio_devices, and/orparent_pids.
Omit all the flags to stop all running processes.exampleLaunch a couple notes, wait 10 seconds, and then stop them:synoteD#3-rpFred:drone
synoteG#3-rpFred:drone
sleep10echo"stopping all notes now!"systop-tnote☞ sy demosy demois a wrapper forsy seqand allows you to play built-in demo sequences. Live recordings of these demos are also for sale onbandcamp.examplePlay the built-in demofire:sydemoplayfireYou can see the full list of built-in demos. for this command viasy demo --help.☞ sy versionsy versionprints the current version ofsaysynthexamplePrint the currently-installed version of saysynth:sy version🤝🏽Development / ContributingIf you're interested in contributing tosaysynthor would like to reportan issue, all development is done ongitlab.  You can also reach out to me viabrian [at] abelson [dot] live. I'm particularly interested in working with interface designers to turn this into a free VST, or something similar.To install viagitfor local development:gitclonehttps://gitlab.com/gltd/saysynth.git# clone this repocdsaysynth&&python-mvenv.venv# create a virtualenv with Python 3.9 or highersource.venv/bin/activate# activate itmakeinstall# install the librarysaysynth--help# check if it workedmaketest# run the testsmakedocs-html&&makedocs-view# compile and view the docs (via: pdoc)