diff options
author | Roland Reichwein <mail@reichwein.it> | 2025-01-19 15:36:24 +0100 |
---|---|---|
committer | Roland Reichwein <mail@reichwein.it> | 2025-01-19 15:36:24 +0100 |
commit | 321eaa65109a6ab18344901dfc4dd8cc4b82367d (patch) | |
tree | 238be56f2cac60dc1c8cdc1598adc855ed323bd7 | |
parent | df1a250beb787e54f81518d2786d78d654f082ba (diff) |
Add clock
-rw-r--r-- | MIDIPlayer.cpp | 6 | ||||
-rw-r--r-- | aplaymidi-mp.c | 74 |
2 files changed, 63 insertions, 17 deletions
diff --git a/MIDIPlayer.cpp b/MIDIPlayer.cpp index 8202850..061b8f6 100644 --- a/MIDIPlayer.cpp +++ b/MIDIPlayer.cpp @@ -11,6 +11,7 @@ #include <string> #include <thread> #include <unordered_set> +#include <stdexcept> namespace bp = boost::process; namespace fs = std::filesystem; @@ -43,7 +44,10 @@ void MIDIPlayer::start() if (m_child.valid() && m_child.running()) { stop(); } else { - m_child = bp::child(fmt::format("aplaymidi -p{} \"{}\"", m_client, m_file).c_str());//, bp::std_out > bp::null); + m_child = bp::child(fmt::format("/home/ernie/code/midiplay/aplaymidi-mp -c -p{} \"{}\"", m_client, m_file).c_str());//, bp::std_out > bp::null); + if (!m_child.valid() || !m_child.running()) { + throw std::runtime_error("aplaymidi not started"); + } } } diff --git a/aplaymidi-mp.c b/aplaymidi-mp.c index 8ad9630..0599f2a 100644 --- a/aplaymidi-mp.c +++ b/aplaymidi-mp.c @@ -77,7 +77,8 @@ static int num_tracks; static struct track *tracks; static int smpte_timing; static int ump_mode; -static int add_clock; +static int clock_mode; +static int time_division; /* prints an error message to stderr */ static void errormsg(const char *msg, ...) @@ -298,6 +299,20 @@ static void skip(int bytes) read_byte(), --bytes; } +static void add_clock(struct track *track, int tick_step, int track_end) +{ + int tick = 0; + struct event *event; + + while (tick <= track_end) { + event = new_event(track, 0); + event->type = SND_SEQ_EVENT_CLOCK; + event->port = 0; + event->tick = tick; + tick += tick_step; + } +} + /* reads one complete track from the file */ static int read_track(struct track *track, int track_end) { @@ -454,10 +469,10 @@ _error: /* reads an entire MIDI file */ static int read_smf(void) { - int header_len, type, time_division, i, err; + int header_len, type, i, err; snd_seq_queue_tempo_t *queue_tempo; - /* the curren position is immediately after the "MThd" id */ + /* the current position is immediately after the "MThd" id */ header_len = read_int(4); if (header_len < 6) { invalid_format: @@ -504,19 +519,23 @@ invalid_format: switch (i) { case 24: snd_seq_queue_tempo_set_tempo(queue_tempo, 500000); - snd_seq_queue_tempo_set_ppq(queue_tempo, 12 * time_division); + time_division *= 12; + snd_seq_queue_tempo_set_ppq(queue_tempo, time_division); break; case 25: snd_seq_queue_tempo_set_tempo(queue_tempo, 400000); - snd_seq_queue_tempo_set_ppq(queue_tempo, 10 * time_division); + time_division *= 10; + snd_seq_queue_tempo_set_ppq(queue_tempo, time_division); break; case 29: /* 30 drop-frame */ snd_seq_queue_tempo_set_tempo(queue_tempo, 100000000); - snd_seq_queue_tempo_set_ppq(queue_tempo, 2997 * time_division); + time_division *= 2997; + snd_seq_queue_tempo_set_ppq(queue_tempo, time_division); break; case 30: snd_seq_queue_tempo_set_tempo(queue_tempo, 500000); - snd_seq_queue_tempo_set_ppq(queue_tempo, 15 * time_division); + time_division *= 15; + snd_seq_queue_tempo_set_ppq(queue_tempo, time_division); break; default: errormsg("%s: invalid number of SMPTE frames per second (%d)", @@ -676,6 +695,11 @@ static int fill_legacy_event(struct event* event, snd_seq_event_t *ev) snd_seq_ev_set_variable(ev, event->data.length, event->sysex); handle_big_sysex(ev); break; + case SND_SEQ_EVENT_CLOCK: + snd_seq_ev_set_fixed(ev); + ev->data.control.channel = event->data.d[0]; + ev->data.control.value = event->data.d[1]; + break; default: fatal("Invalid event type %d!", ev->type); } @@ -759,19 +783,26 @@ static int fill_ump_event(struct event* event, snd_seq_ump_event_t *ump_ev, return 0; } -static void play_midi(void) +static int get_max_tick(void) { - snd_seq_ump_event_t ump_ev; - snd_seq_event_t ev; - int i, max_tick, err; - /* calculate length of the entire file */ - max_tick = -1; + int i, max_tick = -1; for (i = 0; i < num_tracks; ++i) { if (tracks[i].end_tick > max_tick) max_tick = tracks[i].end_tick; } + return max_tick; +} + +static void play_midi(void) +{ + snd_seq_ump_event_t ump_ev; + snd_seq_event_t ev; + int i, max_tick, err; + + max_tick = get_max_tick(); + /* initialize current position in each track */ for (i = 0; i < num_tracks; ++i) tracks[i].current_event = tracks[i].first_event; @@ -900,8 +931,19 @@ static void play_file(void) if (file != stdin) fclose(file); - if (ok) + if (ok) { + if (clock_mode) { + num_tracks += 1; + tracks = realloc(tracks, num_tracks * sizeof(struct track)); + if (!tracks) { + errormsg("out of memory"); + return; + } + memset(&tracks[num_tracks - 1], 0, sizeof(struct track)); + add_clock(&tracks[num_tracks - 1], time_division / 24, get_max_tick()); + } play_midi(); + } cleanup_file_data(); } @@ -960,7 +1002,7 @@ static void version(void) puts("aplaymidi version " SND_UTIL_VERSION_STR); } -#define OPTIONS "hVlp:d:u:" +#define OPTIONS "hVlcp:d:u:" int main(int argc, char *argv[]) { @@ -1004,7 +1046,7 @@ int main(int argc, char *argv[]) fatal("Only MIDI 1.0 is supported"); break; case 'c': - add_clock = 1; + clock_mode = 1; break; default: usage(argv[0]); |