diff --git a/src/AudioGeneratorMIDI.cpp b/src/AudioGeneratorMIDI.cpp
deleted file mode 100644
index e3be2b2..0000000
--- a/src/AudioGeneratorMIDI.cpp
+++ /dev/null
@@ -1,639 +0,0 @@
-/*
- AudioGeneratorMIDI
- Audio output generator that plays MIDI files using a SF2 SoundFont
-
- Copyright (C) 2017 Earle F. Philhower, III
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-/*
- The MIDI processing engine is a heavily modified version of MIDITONES,
- by Len Shustek, https://github.com/LenShustek/miditones .
- Whereas MIDITONES original simply parsed a file beforehand to a byte
- stream to be played by another program, this does the parsing and
- playback in real-time.
-
- Here's his original header/readme w/MIT license, which is subsumed by the
- GPL license of the ESP8266Audio project.
-*/
-
-/***************************************************************************
-
- MIDITONES: Convert a MIDI file into a simple bytestream of notes
-
- -------------------------------------------------------------------------
- The MIT License (MIT)
- Copyright (c) 2011,2013,2015,2016, Len Shustek
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR
- IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-**************************************************************************/
-
-
-#include "AudioGeneratorMIDI.h"
-
-#pragma GCC optimize ("O3")
-
-#define TSF_NO_STDIO
-#define TSF_IMPLEMENTATION
-#include "libtinysoundfont/tsf.h"
-
-/**************** utility routines **********************/
-
-/* announce a fatal MIDI file format error */
-
-void AudioGeneratorMIDI::midi_error(const char *msg, int curpos)
-{
- cb.st(curpos, msg);
-#if 0
- int ptr;
- audioLogger->printf("---> MIDI file error at position %04X (%d): %s\n", (uint16_t) curpos, (uint16_t) curpos, msg);
- /* print some bytes surrounding the error */
- ptr = curpos - 16;
- if (ptr < 0) ptr = 0;
- buffer.seek( buffer.data, ptr );
- for (int i = 0; i < 32; i++) {
- char c;
- buffer.read (buffer.data, &c, 1);
- audioLogger->printf((ptr + i) == curpos ? " [%02X] " : "%02X ", (int) c & 0xff);
- }
- audioLogger->printf("\n");
-#endif
- running = false;
-}
-
-/* check that we have a specified number of bytes left in the buffer */
-
-void AudioGeneratorMIDI::chk_bufdata (int ptr, unsigned long int len) {
- if ((unsigned) (ptr + len) > buflen)
- midi_error ("data missing", ptr);
-}
-
-/* fetch big-endian numbers */
-
-uint16_t AudioGeneratorMIDI::rev_short (uint16_t val) {
- return ((val & 0xff) << 8) | ((val >> 8) & 0xff);
-}
-
-uint32_t AudioGeneratorMIDI::rev_long (uint32_t val) {
- return (((rev_short ((uint16_t) val) & 0xffff) << 16) |
- (rev_short ((uint16_t) (val >> 16)) & 0xffff));
-}
-
-/************** process the MIDI file header *****************/
-
-void AudioGeneratorMIDI::process_header (void) {
- struct midi_header hdr;
- unsigned int time_division;
-
- chk_bufdata (hdrptr, sizeof (struct midi_header));
- buffer.seek (buffer.data, hdrptr);
- buffer.read (buffer.data, &hdr, sizeof (hdr));
- if (!charcmp ((char *) hdr.MThd, "MThd"))
- midi_error ("Missing 'MThd'", hdrptr);
- num_tracks = rev_short (hdr.number_of_tracks);
- time_division = rev_short (hdr.time_division);
- if (time_division < 0x8000)
- ticks_per_beat = time_division;
- else
- ticks_per_beat = ((time_division >> 8) & 0x7f) /* SMTE frames/sec */ *(time_division & 0xff); /* ticks/SMTE frame */
- hdrptr += rev_long (hdr.header_size) + 8; /* point past header to track header, presumably. */
- return;
-}
-
-
-/**************** Process a MIDI track header *******************/
-
-void AudioGeneratorMIDI::start_track (int tracknum) {
- struct track_header hdr;
- unsigned long tracklen;
-
- chk_bufdata (hdrptr, sizeof (struct track_header));
- buffer.seek (buffer.data, hdrptr);
- buffer.read (buffer.data, &hdr, sizeof (hdr));
- if (!charcmp ((char *) (hdr.MTrk), "MTrk"))
- midi_error ("Missing 'MTrk'", hdrptr);
- tracklen = rev_long (hdr.track_size);
- hdrptr += sizeof (struct track_header); /* point past header */
- chk_bufdata (hdrptr, tracklen);
- track[tracknum].trkptr = hdrptr;
- hdrptr += tracklen; /* point to the start of the next track */
- track[tracknum].trkend = hdrptr; /* the point past the end of the track */
-}
-
-unsigned char AudioGeneratorMIDI::buffer_byte (int offset) {
- unsigned char c;
- buffer.seek (buffer.data, offset);
- buffer.read (buffer.data, &c, 1);
- return c;
-}
-
-unsigned short AudioGeneratorMIDI::buffer_short (int offset) {
- unsigned short s;
- buffer.seek (buffer.data, offset);
- buffer.read (buffer.data, &s, sizeof (short));
- return s;
-}
-
-unsigned int AudioGeneratorMIDI::buffer_int32 (int offset) {
- uint32_t i;
- buffer.seek (buffer.data, offset);
- buffer.read (buffer.data, &i, sizeof (i));
- return i;
-}
-
-/* Get a MIDI-style variable-length integer */
-
-unsigned long AudioGeneratorMIDI::get_varlen (int *ptr) {
- /* Get a 1-4 byte variable-length value and adjust the pointer past it.
- These are a succession of 7-bit values with a MSB bit of zero marking the end */
-
- unsigned long val;
- int i, byte;
-
- val = 0;
- for (i = 0; i < 4; ++i) {
- byte = buffer_byte ((*ptr)++);
- val = (val << 7) | (byte & 0x7f);
- if (!(byte & 0x80))
- return val;
- }
- return val;
-}
-
-
-/*************** Process the MIDI track data ***************************/
-
-/* Skip in the track for the next "note on", "note off" or "set tempo" command,
- then record that information in the track status block and return. */
-
-void AudioGeneratorMIDI::find_note (int tracknum) {
- unsigned long int delta_time;
- int event, chan;
- int note, velocity, controller, pressure, pitchbend, instrument;
- int meta_cmd, meta_length;
- unsigned long int sysex_length;
- struct track_status *t;
- const char *tag;
-
- /* process events */
-
- t = &track[tracknum]; /* our track status structure */
- while (t->trkptr < t->trkend) {
-
- delta_time = get_varlen (&t->trkptr);
- t->time += delta_time;
- if (buffer_byte (t->trkptr) < 0x80)
- event = t->last_event; /* using "running status": same event as before */
- else { /* otherwise get new "status" (event type) */
- event = buffer_byte (t->trkptr++);
- }
- if (event == 0xff) { /* meta-event */
- meta_cmd = buffer_byte (t->trkptr++);
- meta_length = get_varlen(&t->trkptr);
- switch (meta_cmd) {
- case 0x00:
- break;
- case 0x01:
- tag = "description";
- goto show_text;
- case 0x02:
- tag = "copyright";
- goto show_text;
- case 0x03:
- tag = "track name";
- goto show_text;
- case 0x04:
- tag = "instrument name";
- goto show_text;
- case 0x05:
- tag = "lyric";
- goto show_text;
- case 0x06:
- tag = "marked point";
- goto show_text;
- case 0x07:
- tag = "cue point";
-show_text:
- break;
- case 0x20:
- break;
- case 0x2f:
- break;
- case 0x51: /* tempo: 3 byte big-endian integer! */
- t->cmd = CMD_TEMPO;
- t->tempo = rev_long (buffer_int32 (t->trkptr - 1)) & 0xffffffL;
- t->trkptr += meta_length;
- return;
- case 0x54:
- break;
- case 0x58:
- break;
- case 0x59:
- break;
- case 0x7f:
- tag = "sequencer data";
- goto show_hex;
- default: /* unknown meta command */
- tag = "???";
-show_hex:
- break;
- }
- t->trkptr += meta_length;
- }
-
- else if (event < 0x80)
- midi_error ("Unknown MIDI event type", t->trkptr);
-
- else {
- if (event < 0xf0)
- t->last_event = event; // remember "running status" if not meta or sysex event
- chan = event & 0xf;
- t->chan = chan;
- switch (event >> 4) {
- case 0x8:
- t->note = buffer_byte (t->trkptr++);
- velocity = buffer_byte (t->trkptr++);
-note_off:
- t->cmd = CMD_STOPNOTE;
- return; /* stop processing and return */
- case 0x9:
- t->note = buffer_byte (t->trkptr++);
- velocity = buffer_byte (t->trkptr++);
- if (velocity == 0) /* some scores use note-on with zero velocity for off! */
- goto note_off;
- t->velocity = velocity;
- t->cmd = CMD_PLAYNOTE;
- return; /* stop processing and return */
- case 0xa:
- note = buffer_byte (t->trkptr++);
- velocity = buffer_byte (t->trkptr++);
- break;
- case 0xb:
- controller = buffer_byte (t->trkptr++);
- velocity = buffer_byte (t->trkptr++);
- break;
- case 0xc:
- instrument = buffer_byte (t->trkptr++);
- midi_chan_instrument[chan] = instrument; // record new instrument for this channel
- break;
- case 0xd:
- pressure = buffer_byte (t->trkptr++);
- break;
- case 0xe:
- pitchbend = buffer_byte (t->trkptr) | (buffer_byte (t->trkptr + 1) << 7);
- t->trkptr += 2;
- break;
- case 0xf:
- sysex_length = get_varlen (&t->trkptr);
- t->trkptr += sysex_length;
- break;
- default:
- midi_error ("Unknown MIDI command", t->trkptr);
- }
- }
- }
- t->cmd = CMD_TRACKDONE; /* no more notes to process */
- ++tracks_done;
-
- // Remove unused warnings..maybe some day we'll look at these
- (void)note;
- (void)controller;
- (void)pressure;
- (void)pitchbend;
- (void)tag;
-}
-
-
-// Open file, parse headers, get ready tio process MIDI
-void AudioGeneratorMIDI::PrepareMIDI(AudioFileSource *src)
-{
- MakeStreamFromAFS(src, &afsMIDI);
- tsf_stream_wrap_cached(&afsMIDI, 32, 64, &buffer);
- buflen = buffer.size (buffer.data);
-
- /* process the MIDI file header */
-
- hdrptr = buffer.tell (buffer.data); /* pointer to file and track headers */
- process_header ();
- printf (" Processing %d tracks.\n", num_tracks);
- if (num_tracks > MAX_TRACKS)
- midi_error ("Too many tracks", buffer.tell (buffer.data));
-
- /* initialize processing of all the tracks */
-
- for (tracknum = 0; tracknum < num_tracks; ++tracknum) {
- start_track (tracknum); /* process the track header */
- find_note (tracknum); /* position to the first note on/off */
- }
-
- notes_skipped = 0;
- tracknum = 0;
- earliest_tracknum = 0;
- earliest_time = 0;
-}
-
-// Parses the note on/offs until we are ready to render some more samples. Then return the
-// total number of samples to render before we need to be called again
-int AudioGeneratorMIDI::PlayMIDI()
-{
- /* Continue processing all tracks, in an order based on the simulated time.
- This is not unlike multiway merging used for tape sorting algoritms in the 50's! */
-
- do { /* while there are still track notes to process */
- static struct track_status *trk;
- static struct tonegen_status *tg;
- static int tgnum;
- static int count_tracks;
- static unsigned long delta_time, delta_msec;
-
- /* Find the track with the earliest event time,
- and output a delay command if time has advanced.
-
- A potential improvement: If there are multiple tracks with the same time,
- first do the ones with STOPNOTE as the next command, if any. That would
- help avoid running out of tone generators. In practice, though, most MIDI
- files do all the STOPNOTEs first anyway, so it won't have much effect.
- */
-
- earliest_time = 0x7fffffff;
-
- /* Usually we start with the track after the one we did last time (tracknum),
- so that if we run out of tone generators, we have been fair to all the tracks.
- The alternate "strategy1" says we always start with track 0, which means
- that we favor early tracks over later ones when there aren't enough tone generators.
- */
-
- count_tracks = num_tracks;
- do {
- if (++tracknum >= num_tracks)
- tracknum = 0;
- trk = &track[tracknum];
- if (trk->cmd != CMD_TRACKDONE && trk->time < earliest_time) {
- earliest_time = trk->time;
- earliest_tracknum = tracknum;
- }
- } while (--count_tracks);
-
- tracknum = earliest_tracknum; /* the track we picked */
- trk = &track[tracknum];
- if (earliest_time < timenow)
- midi_error ("INTERNAL: time went backwards", trk->trkptr);
-
- /* If time has advanced, output a "delay" command */
-
- delta_time = earliest_time - timenow;
- if (delta_time) {
- /* Convert ticks to milliseconds based on the current tempo */
- unsigned long long temp;
- temp = ((unsigned long long) delta_time * tempo) / ticks_per_beat;
- delta_msec = temp / 1000; // get around LCC compiler bug
- if (delta_msec > 0x7fff)
- midi_error ("INTERNAL: time delta too big", trk->trkptr);
- int samples = (((int) delta_msec) * freq) / 1000;
- timenow = earliest_time;
- return samples;
- }
- timenow = earliest_time;
-
- /* If this track event is "set tempo", just change the global tempo.
- That affects how we generate "delay" commands. */
-
- if (trk->cmd == CMD_TEMPO) {
- tempo = trk->tempo;
- find_note (tracknum);
- }
-
- /* If this track event is "stop note", process it and all subsequent "stop notes" for this track
- that are happening at the same time. Doing so frees up as many tone generators as possible. */
-
- else if (trk->cmd == CMD_STOPNOTE)
- do {
- // stop a note
- for (tgnum = 0; tgnum < num_tonegens; ++tgnum) { /* find which generator is playing it */
- tg = &tonegen[tgnum];
- if (tg->playing && tg->track == tracknum && tg->note == trk->note) {
- tsf_note_off (g_tsf, tg->instrument, tg->note);
- tg->playing = false;
- trk->tonegens[tgnum] = false;
- }
- }
- find_note (tracknum); // use up the note
- } while (trk->cmd == CMD_STOPNOTE && trk->time == timenow);
-
- /* If this track event is "start note", process only it.
- Don't do more than one, so we allow other tracks their chance at grabbing tone generators. */
-
- else if (trk->cmd == CMD_PLAYNOTE) {
- bool foundgen = false;
- /* if not, then try for any free tone generator */
- if (!foundgen)
- for (tgnum = 0; tgnum < num_tonegens; ++tgnum) {
- tg = &tonegen[tgnum];
- if (!tg->playing) {
- foundgen = true;
- break;
- }
- }
- if (foundgen) {
- if (tgnum + 1 > num_tonegens_used)
- num_tonegens_used = tgnum + 1;
- tg->playing = true;
- tg->track = tracknum;
- tg->note = trk->note;
- trk->tonegens[tgnum] = true;
- trk->preferred_tonegen = tgnum;
- if (tg->instrument != midi_chan_instrument[trk->chan]) { /* new instrument for this generator */
- tg->instrument = midi_chan_instrument[trk->chan];
- }
- tsf_note_on (g_tsf, tg->instrument, tg->note, trk->velocity / 127.0); // velocity = 0...127
- } else {
- ++notes_skipped;
- }
- find_note (tracknum); // use up the note
- }
- }
- while (tracks_done < num_tracks);
- return -1; // EOF
-}
-
-
-void AudioGeneratorMIDI::StopMIDI()
-{
-
- buffer.close(buffer.data);
- tsf_close(g_tsf);
- printf (" %s %d tone generators were used.\n",
- num_tonegens_used < num_tonegens ? "Only" : "All", num_tonegens_used);
- if (notes_skipped)
- printf
- (" %d notes were skipped because there weren't enough tone generators.\n", notes_skipped);
-
- printf (" Done.\n");
-}
-
-
-bool AudioGeneratorMIDI::begin(AudioFileSource *src, AudioOutput *out)
-{
- // Clear out status variables
- for (int i=0; iSetRate( freq )) return false;
- if (!out->SetBitsPerSample( 16 )) return false;
- if (!out->SetChannels( 1 )) return false;
- if (!out->begin()) return false;
-
- output = out;
- file = src;
-
- running = true;
-
- PrepareMIDI(src);
-
- samplesToPlay = 0;
- numSamplesRendered = 0;
- sentSamplesRendered = 0;
-
- sawEOF = false;
- return running;
-}
-
-
-bool AudioGeneratorMIDI::loop()
-{
- static int c = 0;
-
- if (!running) goto done; // Nothing to do here!
-
- // First, try and push in the stored sample. If we can't, then punt and try later
- if (!output->ConsumeSample(lastSample)) goto done; // Can't send, but no error detected
-
- // Try and stuff the buffer one sample at a time
- do {
- c++;
- if (c%44100 == 0) yield();
-
-play:
-
- if (sentSamplesRendered < numSamplesRendered) {
- lastSample[AudioOutput::LEFTCHANNEL] = samplesRendered[sentSamplesRendered];
- lastSample[AudioOutput::RIGHTCHANNEL] = samplesRendered[sentSamplesRendered];
- sentSamplesRendered++;
- } else if (samplesToPlay) {
- numSamplesRendered = sizeof(samplesRendered)/sizeof(samplesRendered[0]);
- if ((int)samplesToPlay < (int)(sizeof(samplesRendered)/sizeof(samplesRendered[0]))) numSamplesRendered = samplesToPlay;
- tsf_render_short_fast(g_tsf, samplesRendered, numSamplesRendered, 0);
- lastSample[AudioOutput::LEFTCHANNEL] = samplesRendered[0];
- lastSample[AudioOutput::RIGHTCHANNEL] = samplesRendered[0];
- sentSamplesRendered = 1;
- samplesToPlay -= numSamplesRendered;
- } else {
- numSamplesRendered = 0;
- sentSamplesRendered = 0;
- if (sawEOF) {
- running = false;
- } else {
- samplesToPlay = PlayMIDI();
- if (samplesToPlay == -1) {
- sawEOF = true;
- samplesToPlay = freq / 2;
- }
- goto play;
- }
- }
- } while (running && output->ConsumeSample(lastSample));
-
-done:
- file->loop();
- output->loop();
-
- return running;
-}
-
-bool AudioGeneratorMIDI::stop()
-{
- StopMIDI();
- output->stop();
- return true;
-}
-
-
-int AudioGeneratorMIDI::afs_read(void *data, void *ptr, unsigned int size)
-{
- AudioFileSource *s = reinterpret_cast(data);
- return s->read(ptr, size);
-}
-
-int AudioGeneratorMIDI::afs_tell(void *data)
-{
- AudioFileSource *s = reinterpret_cast(data);
- return s->getPos();
-}
-
-int AudioGeneratorMIDI::afs_skip(void *data, unsigned int count)
-{
- AudioFileSource *s = reinterpret_cast(data);
- return s->seek(count, SEEK_CUR);
-}
-
-int AudioGeneratorMIDI::afs_seek(void *data, unsigned int pos)
-{
- AudioFileSource *s = reinterpret_cast(data);
- return s->seek(pos, SEEK_SET);
-}
-
-int AudioGeneratorMIDI::afs_close(void *data)
-{
- AudioFileSource *s = reinterpret_cast(data);
- return s->close();
-}
-
-int AudioGeneratorMIDI::afs_size(void *data)
-{
- AudioFileSource *s = reinterpret_cast(data);
- return s->getSize();
-}
-
-void AudioGeneratorMIDI::MakeStreamFromAFS(AudioFileSource *src, tsf_stream *afs)
-{
- afs->data = reinterpret_cast(src);
- afs->read = &afs_read;
- afs->tell = &afs_tell;
- afs->skip = &afs_skip;
- afs->seek = &afs_seek;
- afs->close = &afs_close;
- afs->size = &afs_size;
-}
-
diff --git a/src/AudioGeneratorMIDI.h b/src/AudioGeneratorMIDI.h
deleted file mode 100644
index 8a1ac3f..0000000
--- a/src/AudioGeneratorMIDI.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- AudioGeneratorMIDI
- Audio output generator that plays MIDI files using a SF2 SoundFont
-
- Copyright (C) 2017 Earle F. Philhower, III
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#ifndef _AUDIOGENERATORMIDI_H
-#define _AUDIOGENERATORMIDI_H
-
-#include "AudioGenerator.h"
-
-#define TSF_NO_STDIO
-#include "libtinysoundfont/tsf.h"
-
-class AudioGeneratorMIDI : public AudioGenerator
-{
- public:
- AudioGeneratorMIDI() { freq=44100; running = false; };
- virtual ~AudioGeneratorMIDI() override {};
- bool SetSoundfont(AudioFileSource *newsf2) {
- if (isRunning()) return false;
- sf2 = newsf2;
- MakeStreamFromAFS(sf2, &afsSF2);
- return true;
- }
- bool SetSampleRate(int newfreq) {
- if (isRunning()) return false;
- freq = newfreq;
- return true;
- }
- virtual bool begin(AudioFileSource *mid, AudioOutput *output) override;
- virtual bool loop() override;
- virtual bool stop() override;
- virtual bool isRunning() override { return running; };
-
- private:
- int freq;
- tsf *g_tsf;
- struct tsf_stream buffer;
- struct tsf_stream afsMIDI;
- struct tsf_stream afsSF2;
- AudioFileSource *sf2;
- AudioFileSource *midi;
-
- protected:
- struct midi_header {
- int8_t MThd[4];
- uint32_t header_size;
- uint16_t format_type;
- uint16_t number_of_tracks;
- uint16_t time_division;
- };
-
- struct track_header {
- int8_t MTrk[4];
- uint32_t track_size;
- };
-
- enum { MAX_TONEGENS = 32, /* max tone generators: tones we can play simultaneously */
- MAX_TRACKS = 24
- }; /* max number of MIDI tracks we will process */
-
- int hdrptr;
- unsigned long buflen;
- int num_tracks;
- int tracks_done = 0;
- int num_tonegens = MAX_TONEGENS;
- int num_tonegens_used = 0;
- unsigned int ticks_per_beat = 240;
- unsigned long timenow = 0;
- unsigned long tempo; /* current tempo in usec/qnote */
- // State needed for PlayMID()
- int notes_skipped = 0;
- int tracknum = 0;
- int earliest_tracknum = 0;
- unsigned long earliest_time = 0;
-
- struct tonegen_status { /* current status of a tone generator */
- bool playing; /* is it playing? */
- char track; /* if so, which track is the note from? */
- char note; /* what note is playing? */
- char instrument; /* what instrument? */
- } tonegen[MAX_TONEGENS];
-
- struct track_status { /* current processing point of a MIDI track */
- int trkptr; /* ptr to the next note change */
- int trkend; /* ptr past the end of the track */
- unsigned long time; /* what time we're at in the score */
- unsigned long tempo; /* the tempo last set, in usec per qnote */
- unsigned int preferred_tonegen; /* for strategy2, try to use this generator */
- unsigned char cmd; /* CMD_xxxx next to do */
- unsigned char note; /* for which note */
- unsigned char chan; /* from which channel it was */
- unsigned char velocity; /* the current volume */
- unsigned char last_event; /* the last event, for MIDI's "running status" */
- bool tonegens[MAX_TONEGENS]; /* which tone generators our notes are playing on */
- } track[MAX_TRACKS];
-
- int midi_chan_instrument[16]; /* which instrument is currently being played on each channel */
-
- /* output bytestream commands, which are also stored in track_status.cmd */
- enum { CMD_PLAYNOTE = 0x90, /* play a note: low nibble is generator #, note is next byte */
- CMD_STOPNOTE = 0x80, /* stop a note: low nibble is generator # */
- CMD_INSTRUMENT = 0xc0, /* change instrument; low nibble is generator #, instrument is next byte */
- CMD_RESTART = 0xe0, /* restart the score from the beginning */
- CMD_STOP = 0xf0, /* stop playing */
- CMD_TEMPO = 0xFE, /* tempo in usec per quarter note ("beat") */
- CMD_TRACKDONE = 0xFF
- }; /* no more data left in this track */
-
-
-
- /* portable string length */
- int strlength (const char *str) {
- int i;
- for (i = 0; str[i] != '\0'; ++i);
- return i;
- }
-
-
- /* match a constant character sequence */
-
- int charcmp (const char *buf, const char *match) {
- int len, i;
- len = strlength (match);
- for (i = 0; i < len; ++i)
- if (buf[i] != match[i])
- return 0;
- return 1;
- }
-
- unsigned char buffer_byte (int offset);
- unsigned short buffer_short (int offset);
- unsigned int buffer_int32 (int offset);
-
- void midi_error (const char *msg, int curpos);
- void chk_bufdata (int ptr, unsigned long int len);
- uint16_t rev_short (uint16_t val);
- uint32_t rev_long (uint32_t val);
- void process_header (void);
- void start_track (int tracknum);
-
- unsigned long get_varlen (int *ptr);
- void find_note (int tracknum);
- void PrepareMIDI(AudioFileSource *src);
- int PlayMIDI();
- void StopMIDI();
-
- // tsf_stream <-> AudioFileSource
- static int afs_read(void *data, void *ptr, unsigned int size);
- static int afs_tell(void *data);
- static int afs_skip(void *data, unsigned int count);
- static int afs_seek(void *data, unsigned int pos);
- static int afs_close(void *data);
- static int afs_size(void *data);
- void MakeStreamFromAFS(AudioFileSource *src, tsf_stream *afs);
-
- int samplesToPlay;
- bool sawEOF;
- int numSamplesRendered;
- int sentSamplesRendered ;
- short samplesRendered[256];
-};
-
-
-#endif
-
diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp
index 88ef7c5..762d91e 100644
--- a/src/AudioOutputI2S.cpp
+++ b/src/AudioOutputI2S.cpp
@@ -180,7 +180,7 @@ bool AudioOutputI2S::begin(bool txDAC)
if (output_mode == INTERNAL_DAC)
{
#if SOC_I2S_SUPPORTS_DAC
- comm_fmt = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S_MSB;
+ comm_fmt = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_I2S;
#endif
}