summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2025-01-19 15:36:24 +0100
committerRoland Reichwein <mail@reichwein.it>2025-01-19 15:36:24 +0100
commit321eaa65109a6ab18344901dfc4dd8cc4b82367d (patch)
tree238be56f2cac60dc1c8cdc1598adc855ed323bd7
parentdf1a250beb787e54f81518d2786d78d654f082ba (diff)
Add clock
-rw-r--r--MIDIPlayer.cpp6
-rw-r--r--aplaymidi-mp.c74
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]);