Skip to content

Commit 7d99e6b

Browse files
BREAKING: Re-port MIDI, faster, lower memory, ESP32 support (earlephilhower#790)
* Pull untouched upstream TinySoundFont Start from the upstream TinySoundFont by @schellingb at https://github.com/schellingb/TinySoundFont and rearchitect the MIDI processing. * Convert to PROGMEM-based SoundFont structures. This makes it much faster to access the SoundFont and also removes all the static RAM usage. The samples, the regions, the instruments are all now in ROM. Only the dynamic voices and related info takes up RAM. No caching. * (Re)convert to fixed point math. TSF upstream is built for systems with real floating point units (and produces great sound with it!), but processors like the Pico, ESP8266, and several models of ESP32 don't have one so emulate FP in *extremely* slow SW. Use fixed point (integer) representations for the inner loop and wherever possible to avoid `float` math. For processors like the Pico 2 or original ESP32 with hardware FPUs this still increases performance since integer is still much faster. * Redo the example and add default SF2s Rewrite the MIDI examples to use PROGMEM for both SF2 and MID file. It simplifies life for the casual user and me. * Breaking change The MIDI object now has a `midi::SetSoundFont(tsf *)` instead of a `midi::SetSoundfont(AudioFileSource *)`. It no longer supports reading SF2 from LittleFS or SD.
1 parent 3e099fe commit 7d99e6b

31 files changed

+64533
-2836
lines changed

.github/workflows/pr-or-master-push.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ jobs:
155155
- name: Run codespell
156156
uses: codespell-project/actions-codespell@406322ec52dd7b488e48c1c4b82e2a8b3a1bf630 # v2.1
157157
with:
158-
skip: ./src/libmad,./src/libhelix-aac,./src/libopus,./src/libflac,./lib/opus
158+
skip: ./src/libmad,./src/libhelix-aac,./src/libopus,./src/libflac,./lib/opus,./src/libtinysoundfont,./lib/TinySoundFont
159159
ignore_words_list: ESP8266,esp8266,esp,dout,DOUT,ser,ans,inout,numer,hist
160160
- name: Run astyle on all code/examples
161161
run: |

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "lib/opus"]
22
path = lib/opus
33
url = https://gitlab.xiph.org/xiph/opus.git
4+
[submodule "lib/TinySoundFont"]
5+
path = lib/TinySoundFont
6+
url = https://github.com/earlephilhower/TinySoundFont.git

examples/PlayMIDIFromLittleFS/PlayMIDIFromLittleFS.ino

Lines changed: 0 additions & 53 deletions
This file was deleted.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// PlayMIDIFromROM
2+
// Released to the public domain (2025) by Earle F. Philhower, III <earlephilhower@yahoo.com>
3+
#include <Arduino.h>
4+
#ifdef ESP8266
5+
#include <ESP8266WiFi.h>
6+
#else
7+
#include <WiFi.h>
8+
#endif
9+
#include <ESP8266Audio.h>
10+
11+
// Define the SF2 (SoundFont) to use. Will be stored in PROGMEM as global _tsf
12+
#ifdef ESP8266
13+
// The ESP8266 has a 1MB ROM limit so use a smaller SF2 file
14+
#include <libtinysoundfont/scratch2010.h>
15+
#else
16+
// Pico and ESP32 can have up to 16MB ROMs, use the 1M General MIDI (1mgm) font or your own
17+
// For ESP32 be sure to use HUGE APP or another partition mode which allows you to have sketches larger than 1-2MB
18+
19+
#include <libtinysoundfont/1mgm.h>
20+
#endif
21+
22+
// Select one of the following in order of CPU limitations. You can also use your own.
23+
//#include "furelise_mid.h"
24+
//#include "venture_mid.h"
25+
#include "jm_mozdi_mid.h"
26+
27+
// Note that the .MID file does NOT need to be in PROGMEM, it just makes the examples easier to use (no FS upload required).
28+
AudioFileSourcePROGMEM *midfile;
29+
30+
// Any AudioOutput* would work here (AudioOutputPWM, AudioOutputI2SNoDAT, etc.)
31+
AudioOutputI2S *dac;
32+
33+
// The MIDI wavetable synthesizer
34+
AudioGeneratorMIDI *midi;
35+
36+
37+
void setup() {
38+
WiFi.mode(WIFI_OFF);
39+
40+
Serial.begin(115200);
41+
Serial.println("Starting up...\n");
42+
43+
audioLogger = &Serial;
44+
midfile = new AudioFileSourcePROGMEM(_mid, sizeof(_mid));
45+
46+
dac = new AudioOutputI2S();
47+
dac->SetPinout(0, 1, 2); // Adjust to your I2S DAC pinout
48+
dac->SetGain(0.5);
49+
midi = new AudioGeneratorMIDI();
50+
midi->SetSoundFont(&_tsf);
51+
// If you get audio clicks/break up then you can decrease the sample rate. You can also try increasing this if your MIDs are simple enough and the chip fast enough
52+
midi->SetSampleRate(22050);
53+
54+
Serial.printf("BEGIN...\n");
55+
midi->begin(midfile, dac);
56+
}
57+
58+
void loop() {
59+
static int cnt, lcnt;
60+
if (midi->isRunning()) {
61+
if (!midi->loop()) {
62+
midi->stop();
63+
} else {
64+
if (++cnt == 10000) {
65+
Serial.printf("Loop %d\n", ++lcnt * 1000);
66+
cnt = 0;
67+
}
68+
}
69+
} else {
70+
Serial.printf("MIDI done\n");
71+
delay(1000);
72+
}
73+
}

examples/PlayMIDIFromROM/furelise_mid.h

Lines changed: 925 additions & 0 deletions
Large diffs are not rendered by default.

examples/PlayMIDIFromROM/jm_mozdi_mid.h

Lines changed: 2583 additions & 0 deletions
Large diffs are not rendered by default.

examples/PlayMIDIFromROM/venture_mid.h

Lines changed: 639 additions & 0 deletions
Large diffs are not rendered by default.

examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino

Lines changed: 0 additions & 60 deletions
This file was deleted.
-1.04 MB
Binary file not shown.
-10.8 KB
Binary file not shown.

0 commit comments

Comments
 (0)