AMY - A high-performance fixed-point Music synthesizer librarY
700
stars
2,966
commits
C
primary language
Sep 9, 2026
updated
AMY is a fast and small music synthesizer library written in C with (so far) Python, Arduino, Javascript and GDScript bindings. It can easily be embedded into almost any program, architecture or microcontroller.
It can be used as a very good analog-type synthesizer (Juno-6 style) a FM synthesizer (DX7 style), a partial breakpoint synthesizer (Alles machine or Atari AMY), a very good synthesized piano, a sampler or wavetable synth (where you load in your own PCM data), a drum machine (808-style PCM samples are included), or as a lower level toolkit to make your own combinations of oscillators, filters, LFOs and effects. AMY supports MIDI internally and can manage synthesizer note messages for you, including voice stealing and assigning controller changes.
NEW! Check out the AMYboard - the perfect hardware to run AMY on.
We've run AMY on:
AMY is highly optimized for polyphony and poly-timbral operation on even the lowest power and constrained RAM microcontroller but can scale to as many oscillators as you want.
AMY powers the multi-speaker mesh synthesizer Alles, as well as the Tulip Creative Computer. Let us know if you use AMY for your own projects and we'll add it here!
AMY was built by DAn Ellis and Brian Whitman, and would love your contributions.
Chat about AMY on our Discord!
AMY supports
The FM synth provides a Python library, fm.py that can convert any DX7 patch into an AMY patch, including directly from DX7 sysex (.SYX) files with fm.load_syx() — see Loading DX7 sysex files.
The Juno-6 emulation provides juno.py and can read in Juno-6 SYSEX patches and convert them into AMY patches.
The partials-driven piano voice and the code to generate the partials are described here.
AMY will run on many modern microcontrollers under Arduino. On most platforms, we handle sending audio out to an I2S interface and handling MIDI input. Some platforms support more features than others.
Please see our more detailed Getting Started on Arduino page for more details.
You can import amy in Python and have it render either out to your speakers or to a buffer of samples you can process on your own. To install the amy library, run pip install .. You can also run make test to install the library and run a series of tests.
Please see our interactive AMY tutorial for more tips on using AMY
We provide an emscripten port of AMY that runs in Javascript. See the AMY web demos. To build for the web, use make docs/amy.js. It will generate amy.js in docs/.
To use AMY in your own software, simply copy the .c and .h files in src to your program and compile them. No other libraries should be required to synthesize audio in AMY.
To run a simple C example on many platforms:
make
./amy-example # you should hear tones out your default speaker, use ./amy-example -h for options
Please see our interactive AMY tutorial for more tips on using AMY
AMY provides a MIDI mode by default that lets you control many parts of AMY over MIDI. You can even control the underlying oscillators over SYSEX. See our MIDI documentation for more details. The simplest way to use AMY is to start it and them play MIDI notes to it. By default, AMY boots with a Juno-6 patch 0 on MIDI channel 1.
In Python:
>>> import amy; amy.live(default_synths=1)
>>> # play MIDI notes using system MIDI
In C:
amy_config = amy_default_config()
amy_start(amy_config);
amy_live_start();
// play MIDI notes using system MIDI or UART MIDI on microcontrollers
In Javascript (see minimal.html for the full example):
<script type="text/javascript" src="amy.js"></script>
<script type="text/javascript" src="amy_connector.js"></script>
<script>
// You have to start AMY on a user click for audio to work
document.body.addEventListener('click', amy_js_start, true);
</script>
<!-- Now play MIDI notes over webMIDI -->
AMY supports note commands, some MIDI controllers, and program changes to change the patch.
Presumably you'd like to explicitly tell AMY what to play. You can control AMY from almost anything. We mostly work in Python, C or Javascript, but AMY has been built to work with anything that can send a string.
AMY has two API interfaces: wire messages and amy_event. An AMY wire message is a string that looks like v0n50l1K130i1iv4Z, with each letter corresponding to a field (like v0 means oscillator 0, n50 means midi note 50, K130 means patch number 130, etc.) Wire messages are converted into amy_events within AMY once received.
So in C, or JS, you'd fill an amy_event struct to define a single event of the synthesizer. For example, that wire message above is:
amy_event e = amy_default_event();
e.osc = 0;
e.patch_number = 130;
e.velocity = 1;
e.midi_note = 50;
e.synth = 1;
e.num_voices = 4;
amy_add_event(&e);
In Python, we provide the amy package that generates wire messages from a Pythonic amy.send(**kwargs). In Python, you'd do
amy.send(osc=0, patch=130, vel=1, note=50, synth=1, num_voices=4)
Wire messages are used in AMY as a compact serialization of AMY events and become useful when communicating between AMY and other programs that may not be linked together. For example, Alles uses wire messages over Wi-Fi UDP to control a mesh of AMY synthesizers. Tulip Web sends wire messages from the Micropython web process to the AudioWorklet running AMY on the web. We also store the Juno-6 and DX7 patches within AMY itself using wire messages, which helps keep the code size down.
You can also send wire messages over SYSEX to AMY, if you want to control AMY over MIDI beyond the default MIDI mode. See our MIDI documentation for more details.
It's good to understand what wire messages are but you don't need to construct them directly if you're linking AMY in your software. Use amy_event or amy.send() in Python to control AMY for almost all use cases.
C
83.8%
Jupyter Notebook
8.7%
Python
5.8%
AMY - A high-performance fixed-point Music synthesizer librarY
700
stars
2,966
commits
C
primary language
Sep 9, 2026
updated
AMY is a fast and small music synthesizer library written in C with (so far) Python, Arduino, Javascript and GDScript bindings. It can easily be embedded into almost any program, architecture or microcontroller.
It can be used as a very good analog-type synthesizer (Juno-6 style) a FM synthesizer (DX7 style), a partial breakpoint synthesizer (Alles machine or Atari AMY), a very good synthesized piano, a sampler or wavetable synth (where you load in your own PCM data), a drum machine (808-style PCM samples are included), or as a lower level toolkit to make your own combinations of oscillators, filters, LFOs and effects. AMY supports MIDI internally and can manage synthesizer note messages for you, including voice stealing and assigning controller changes.
NEW! Check out the AMYboard - the perfect hardware to run AMY on.
We've run AMY on:
AMY is highly optimized for polyphony and poly-timbral operation on even the lowest power and constrained RAM microcontroller but can scale to as many oscillators as you want.
AMY powers the multi-speaker mesh synthesizer Alles, as well as the Tulip Creative Computer. Let us know if you use AMY for your own projects and we'll add it here!
AMY was built by DAn Ellis and Brian Whitman, and would love your contributions.
Chat about AMY on our Discord!
AMY supports
The FM synth provides a Python library, fm.py that can convert any DX7 patch into an AMY patch, including directly from DX7 sysex (.SYX) files with fm.load_syx() — see Loading DX7 sysex files.
The Juno-6 emulation provides juno.py and can read in Juno-6 SYSEX patches and convert them into AMY patches.
The partials-driven piano voice and the code to generate the partials are described here.
AMY will run on many modern microcontrollers under Arduino. On most platforms, we handle sending audio out to an I2S interface and handling MIDI input. Some platforms support more features than others.
Please see our more detailed Getting Started on Arduino page for more details.
You can import amy in Python and have it render either out to your speakers or to a buffer of samples you can process on your own. To install the amy library, run pip install .. You can also run make test to install the library and run a series of tests.
Please see our interactive AMY tutorial for more tips on using AMY
We provide an emscripten port of AMY that runs in Javascript. See the AMY web demos. To build for the web, use make docs/amy.js. It will generate amy.js in docs/.
To use AMY in your own software, simply copy the .c and .h files in src to your program and compile them. No other libraries should be required to synthesize audio in AMY.
To run a simple C example on many platforms:
make
./amy-example # you should hear tones out your default speaker, use ./amy-example -h for options
Please see our interactive AMY tutorial for more tips on using AMY
AMY provides a MIDI mode by default that lets you control many parts of AMY over MIDI. You can even control the underlying oscillators over SYSEX. See our MIDI documentation for more details. The simplest way to use AMY is to start it and them play MIDI notes to it. By default, AMY boots with a Juno-6 patch 0 on MIDI channel 1.
In Python:
>>> import amy; amy.live(default_synths=1)
>>> # play MIDI notes using system MIDI
In C:
amy_config = amy_default_config()
amy_start(amy_config);
amy_live_start();
// play MIDI notes using system MIDI or UART MIDI on microcontrollers
In Javascript (see minimal.html for the full example):
<script type="text/javascript" src="amy.js"></script>
<script type="text/javascript" src="amy_connector.js"></script>
<script>
// You have to start AMY on a user click for audio to work
document.body.addEventListener('click', amy_js_start, true);
</script>
<!-- Now play MIDI notes over webMIDI -->
AMY supports note commands, some MIDI controllers, and program changes to change the patch.
Presumably you'd like to explicitly tell AMY what to play. You can control AMY from almost anything. We mostly work in Python, C or Javascript, but AMY has been built to work with anything that can send a string.
AMY has two API interfaces: wire messages and amy_event. An AMY wire message is a string that looks like v0n50l1K130i1iv4Z, with each letter corresponding to a field (like v0 means oscillator 0, n50 means midi note 50, K130 means patch number 130, etc.) Wire messages are converted into amy_events within AMY once received.
So in C, or JS, you'd fill an amy_event struct to define a single event of the synthesizer. For example, that wire message above is:
amy_event e = amy_default_event();
e.osc = 0;
e.patch_number = 130;
e.velocity = 1;
e.midi_note = 50;
e.synth = 1;
e.num_voices = 4;
amy_add_event(&e);
In Python, we provide the amy package that generates wire messages from a Pythonic amy.send(**kwargs). In Python, you'd do
amy.send(osc=0, patch=130, vel=1, note=50, synth=1, num_voices=4)
Wire messages are used in AMY as a compact serialization of AMY events and become useful when communicating between AMY and other programs that may not be linked together. For example, Alles uses wire messages over Wi-Fi UDP to control a mesh of AMY synthesizers. Tulip Web sends wire messages from the Micropython web process to the AudioWorklet running AMY on the web. We also store the Juno-6 and DX7 patches within AMY itself using wire messages, which helps keep the code size down.
You can also send wire messages over SYSEX to AMY, if you want to control AMY over MIDI beyond the default MIDI mode. See our MIDI documentation for more details.
It's good to understand what wire messages are but you don't need to construct them directly if you're linking AMY in your software. Use amy_event or amy.send() in Python to control AMY for almost all use cases.
C
83.8%
Jupyter Notebook
8.7%
Python
5.8%