<commit_before>* thi.ng/synstack

Softsynth engine for tiny & not-so-tiny devices...

** Contents                                                        :toc_3_gh:
 - [[#thingsynstack][thi.ng/synstack]]
     - [[#overview][Overview]]
         - [[#node-dag-synth-engine][Node DAG synth engine]]
         - [[#forth-like-vm-based-synth][Forth-like VM based synth]]
     - [[#build-instructions][Build instructions]]
     - [[#examples][Examples]]
         - [[#interactive-examples][Interactive examples]]
         - [[#forth-repl][Forth REPL]]
     - [[#contributors][Contributors]]
     - [[#license][License]]

** Overview

[[./assets/thing-synstack.jpg]]

Check out: [[http://soundcloud.com/forthcharlie/sets/stm32f4][Demo set with 40+ tracks on Soundcloud]]!

Full project release forthcoming...

Please visit [[https://hackaday.io/project/9374-stm32f4f7-synstack][project log @ Hackaday]] for interim updates, including a
PDF with more project details. Thanks!

This repo currently contains two different experimental & easily
extensible implementations of a modular soft synth engine, both
written in portable C11 and originally developed for the STM32F4/F7
platform. However, for practical reasons (repo size, easier debugging
and dev workflow), both versions currently included here were prepared
without STM specifics, have been tested on OSX & Linux and [[#examples][include
several examples]]. Demo file size after stripping is between ~22-40KB
(for 32bit, bit larger for 64bit).

The sub-directories contain:

*** Node DAG synth engine

- =src= - an earlier (2nd or 3rd) iteration of the CTSS synth engine,
  using block based operators & node DAG (directed acyclic graph):
  - 10 oscillators (incl. formant & karplus-strong, polyBlep antialiasing)
  - flexibile LFO setup (global LFO & arbitrary per voice)
  - filters (biquad, IIR LP/HP/BP, formant)
  - ADSR
  - foldback distortion
  - buffer ops (sum, product, product sum)
  - mono / stereo delay lines w/ feedback
  - mono / stereo mixdowns (int16 & float)
- =examples= - examples for this version of the synth (using
  Portaudio, see below)

*** Forth-like VM based synth

(not embracing ANS Forth standard here):

- =src_vm= - actual stack VM, interpreter & compiler w/ basic
  inlining, REPL, core Forth dictionary & basic synth operators (still
  need to port more from =src=)
- =examples_vm= - Forth examples (see below)

** Build instructions

Requirements:

- [[https://premake.github.io/][Premake5]]
- [[http://www.gnu.org/software/make/][GNU Make]]
- GCC / Clang (w/ C11 support)

The library itself has no 3rd party dependencies. Some of the examples
however use these additional libraries:

- [[https://github.com/thi-ng/ct-head][ct-head]] (included as submodule)
- [[http://portaudio.com][Portaudio]] (on OSX can be installed via =brew=)
- libncurses (part of OSX & Linux)

#+BEGIN_SRC shell
git clone --recursive https://github.com/thi-ng/synstack

cd synstack

premake5 gmake

make -f ctss_old.make config=release_sse

make -f ctss_vm.make config=release_sse
#+END_SRC

** Examples
*** Interactive examples

Use the above build instructions to build all components & examples.
Almost all demos in =examples= implement a simple randomized sequence
playback (some with multiple voices) and are using the same
interactive controls:

| *Key* | *Description*      |
|-------+--------------------|
| =-=   | dec delay feedback |
| =+=   | inc delay feedback |
| =[=   | pitch -2 semitones |
| =]=   | pitch +2 semitones |
| =;=   | pitch -12          |
| '     | pitch +12          |
| =q=   | quit               |

The two exceptions are:

- [[./examples/synth_keys.c][synth_keys]] - play a new note with each keypress (fixed sequence, =q= to quit)
- [[./examples/synth_render.c][synth_render]] - non-interactive demo, creates /sound.wav file (runtime ~20secs)

#+BEGIN_SRC shell
  # if you followed above build instructions, the demos can be launched like:
  bin/release/synth_spiral
#+END_SRC

*** Forth REPL

To launch the VM with input file. Also see [[./examples_vm/bass-seq.fs][example source code]]. In
this mode the VM goes into playback mode and is non-interactive (hit
=Return= to quit).

#+BEGIN_SRC shell
  bin/release/repl examples_vm/bass-seq.fs
#+END_SRC

To launch the Forth REPL in interactive mode:

#+BEGIN_SRC shell
  rlwrap bin/release/repl
#+END_SRC

There'll be alot of output initially (inlining statistics by the
compiler), but no visible input prompt. Try some of the following (hit
return after each line, comment lines are prefixed with '\')...

#+BEGIN_SRC forth
  \ evaluate expression
  \ forth uses RPN, the '.' word pops & prints the top stack item
  \ forth is a hybrid between interpreted & compiled execution
  1 2 + .
  \ 3

  \ define new word (here to calculate a * b + c)
  \ the (...) form is a stack effect comment:
  \ here it means the word consumes 3 items from the stack
  \ and after execution a new item (result) is on the stack
  : madd ( a b c -- x ) -rot * + ;
  3 5 10 madd .
  \ 25

  \ the VM differentiates between int & float based math
  \ float ops are prefixed with 'f'
  : maddf -rot f* f+ ;
  3.f 5.f 10.f maddf .f
  \ 25.0

  \ store values in "variables" (labelled addresses)
  23 var> foo !
  \ get var value
  foo @ .
  \ 23

  \ by default the VM includes the dictionary of synth related words
  \ (defined in /src_vm/synth_dict & various C files in /src_vm)
  \ for example note names map to their frequency
  A4 .f
  \ 440.000000

  \ convert frequency to ratio of sample rate
  A4 hz .f
  \ 0.062689

  \ allocate memory for note/chord lookup table
  C3 E3 G3 A3 4 dup allot dup var> chord ! swap ds>dict!

  \ define word to randomly choose note from chord
  : rand-chord-note ( -- freq ) 0 4 rand seq @ + @ ;

  \ call several times
  rand-chord-note .f
  rand-chord-note .f
  rand-chord-note .f

  \ display data stack contents with .s
  1 2 3 .s

  \ display VM stats
  .vm

  \ display list & addresses of all words currently defined
  .words

  \ display hexdump of VM memory
  .mem
#+END_SRC

** Contributors
<commit_msg>add disassemble example to readme<commit_after>* thi.ng/synstack

Softsynth engine for tiny & not-so-tiny devices...

** Contents                                                        :toc_3_gh:
 - [[#thingsynstack][thi.ng/synstack]]
     - [[#overview][Overview]]
         - [[#node-dag-synth-engine][Node DAG synth engine]]
         - [[#forth-like-vm-based-synth][Forth-like VM based synth]]
     - [[#build-instructions][Build instructions]]
     - [[#examples][Examples]]
         - [[#interactive-examples][Interactive examples]]
         - [[#forth-repl][Forth REPL]]
     - [[#contributors][Contributors]]
     - [[#license][License]]

** Overview

[[./assets/thing-synstack.jpg]]

Check out: [[http://soundcloud.com/forthcharlie/sets/stm32f4][Demo set with 40+ tracks on Soundcloud]]!

Full project release forthcoming...

Please visit [[https://hackaday.io/project/9374-stm32f4f7-synstack][project log @ Hackaday]] for interim updates, including a
PDF with more project details. Thanks!

This repo currently contains two different experimental & easily
extensible implementations of a modular soft synth engine, both
written in portable C11 and originally developed for the STM32F4/F7
platform. However, for practical reasons (repo size, easier debugging
and dev workflow), both versions currently included here were prepared
without STM specifics, have been tested on OSX & Linux and [[#examples][include
several examples]]. Demo file size after stripping is between ~22-40KB
(for 32bit, bit larger for 64bit).

The sub-directories contain:

*** Node DAG synth engine

- =src= - an earlier (2nd or 3rd) iteration of the CTSS synth engine,
  using block based operators & node DAG (directed acyclic graph):
  - 10 oscillators (incl. formant & karplus-strong, polyBlep antialiasing)
  - flexibile LFO setup (global LFO & arbitrary per voice)
  - filters (biquad, IIR LP/HP/BP, formant)
  - ADSR
  - foldback distortion
  - buffer ops (sum, product, product sum)
  - mono / stereo delay lines w/ feedback
  - mono / stereo mixdowns (int16 & float)
- =examples= - examples for this version of the synth (using
  Portaudio, see below)

*** Forth-like VM based synth

(not embracing ANS Forth standard here):

- =src_vm= - actual stack VM, interpreter & compiler w/ basic
  inlining, REPL, core Forth dictionary & basic synth operators (still
  need to port more from =src=)
- =examples_vm= - Forth examples (see below)

** Build instructions

Requirements:

- [[https://premake.github.io/][Premake5]]
- [[http://www.gnu.org/software/make/][GNU Make]]
- GCC / Clang (w/ C11 support)

The library itself has no 3rd party dependencies. Some of the examples
however use these additional libraries:

- [[https://github.com/thi-ng/ct-head][ct-head]] (included as submodule)
- [[http://portaudio.com][Portaudio]] (on OSX can be installed via =brew=)
- libncurses (part of OSX & Linux)

#+BEGIN_SRC shell
git clone --recursive https://github.com/thi-ng/synstack

cd synstack

premake5 gmake

make -f ctss_old.make config=release_sse

make -f ctss_vm.make config=release_sse
#+END_SRC

** Examples
*** Interactive examples

Use the above build instructions to build all components & examples.
Almost all demos in =examples= implement a simple randomized sequence
playback (some with multiple voices) and are using the same
interactive controls:

| *Key* | *Description*      |
|-------+--------------------|
| =-=   | dec delay feedback |
| =+=   | inc delay feedback |
| =[=   | pitch -2 semitones |
| =]=   | pitch +2 semitones |
| =;=   | pitch -12          |
| '     | pitch +12          |
| =q=   | quit               |

The two exceptions are:

- [[./examples/synth_keys.c][synth_keys]] - play a new note with each keypress (fixed sequence, =q= to quit)
- [[./examples/synth_render.c][synth_render]] - non-interactive demo, creates /sound.wav file (runtime ~20secs)

#+BEGIN_SRC shell
  # if you followed above build instructions, the demos can be launched like:
  bin/release/synth_spiral
#+END_SRC

*** Forth REPL

To launch the VM with input file. Also see [[./examples_vm/bass-seq.fs][example source code]]. In
this mode the VM goes into playback mode and is non-interactive (hit
=Return= to quit).

#+BEGIN_SRC shell
  bin/release/repl examples_vm/bass-seq.fs
#+END_SRC

To launch the Forth REPL in interactive mode:

#+BEGIN_SRC shell
  rlwrap bin/release/repl
#+END_SRC

There'll be alot of output initially (inlining statistics by the
compiler), but no visible input prompt. Try some of the following (hit
return after each line, comment lines are prefixed with '\')...

#+BEGIN_SRC forth
  \ evaluate expression
  \ forth uses RPN, the '.' word pops & prints the top stack item
  \ forth is a hybrid between interpreted & compiled execution
  1 2 + .
  \ 3

  \ define new word (here to calculate a * b + c)
  \ the (...) form is a stack effect comment:
  \ here it means the word consumes 3 items from the stack
  \ and after execution a new item (result) is on the stack
  : madd ( a b c -- x ) -rot * + ;
  3 5 10 madd .
  \ 25

  \ the VM differentiates between int & float based math
  \ float ops are prefixed with 'f'
  : maddf -rot f* f+ ;
  3.f 5.f 10.f maddf .f
  \ 25.0

  \ store values in "variables" (labelled addresses)
  23 var> foo !
  \ get var value
  foo @ .
  \ 23

  \ by default the VM includes the dictionary of synth related words
  \ (defined in /src_vm/synth_dict & various C files in /src_vm)
  \ for example note names map to their frequency
  A4 .f
  \ 440.000000

  \ convert frequency to ratio of sample rate
  A4 hz .f
  \ 0.062689

  \ allocate memory for note/chord lookup table
  C3 E3 G3 A3 4 dup allot dup var> chord ! swap ds>dict!

  \ define word to randomly choose note from chord
  : rand-chord-note ( -- freq ) 0 4 rand seq @ + @ ;

  \ call several times
  rand-chord-note .f
  rand-chord-note .f
  rand-chord-note .f

  \ disassemble word
  see> rand-chord-note
  \ 0x000004da :0x0301a88a docolon
  \ 0x000004db :0x00000004 lit 0x00000000 
  \ 0x000004dd :0x00000004 lit 0x00000004 
  \ 0x000004df :0x00000081 rand
  \ 0x000004e0 :0x00000004 lit 0x000004d3 
  \ 0x000004e2 :0x0000002a @
  \ 0x000004e3 :0x0000004b + 0x0000002a (0x0000050e )
  \ 0x000004e5 :0x00000002 ret

  \ display data stack contents with .s
  1 2 3 .s

  \ display VM stats
  .vm

  \ display list & addresses of all words currently defined
  .words

  \ display hexdump of VM memory
  .mem
#+END_SRC

** Contributors

{'fraction_non_alphanumeric': 0.10971811866166255, 'fraction_numerical': 0.0289068114669009, 'mean_word_length': 3.1156753204074925, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 10, 'https://': 8, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 6, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '850029', 'n_tokens_mistral': 4347, 'n_tokens_neox': 3912, 'n_words': 1467}