diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2024-10-07 19:30:56 +0200 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2024-10-07 19:30:56 +0200 |
| commit | 40a899bd6ee536eae093337bf2d0dcc8db4e46f1 (patch) | |
| tree | 485ace3e6fd28b91f394efd277732651e10824d8 /portmidi/pm_test/midiclock.c | |
| parent | 6fc4bddfdf8e056469f316c1a0fe488efbb4253a (diff) | |
| download | ttdaw-40a899bd6ee536eae093337bf2d0dcc8db4e46f1.tar.gz | |
Moved example code examples folder
Diffstat (limited to 'portmidi/pm_test/midiclock.c')
| -rw-r--r-- | portmidi/pm_test/midiclock.c | 282 |
1 files changed, 0 insertions, 282 deletions
diff --git a/portmidi/pm_test/midiclock.c b/portmidi/pm_test/midiclock.c deleted file mode 100644 index f0a6897..0000000 --- a/portmidi/pm_test/midiclock.c +++ /dev/null @@ -1,282 +0,0 @@ -/* miditime.c -- a test program that sends midi clock and MTC */ - -#include "portmidi.h" -#include "porttime.h" -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <ctype.h> - -#ifndef false -#define false 0 -#define true 1 -#endif - -#define private static -typedef int boolean; - -#define MIDI_TIME_CLOCK 0xf8 -#define MIDI_START 0xfa -#define MIDI_CONTINUE 0xfb -#define MIDI_STOP 0xfc -#define MIDI_Q_FRAME 0xf1 - -#define OUTPUT_BUFFER_SIZE 0 -#define DRIVER_INFO NULL -#define TIME_PROC ((PmTimeProcPtr) Pt_Time) -#define TIME_INFO NULL -#define LATENCY 0 -#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */ - -#define STRING_MAX 80 /* used for console input */ - -/* to determine ms per clock: - * time per beat in seconds = 60 / tempo - * multiply by 1000 to get time per beat in ms: 60000 / tempo - * divide by 24 CLOCKs per beat: (60000/24) / tempo - * simplify: 2500 / tempo - */ -#define TEMPO_TO_CLOCK 2500.0 - -boolean done = false; -PmStream *midi; -/* shared flags to control callback output generation: */ -boolean clock_running = false; -boolean send_start_stop = false; -boolean time_code_running = false; -boolean active = false; /* tells callback to do its thing */ -float tempo = 60.0F; -/* protocol for handing off portmidi to callback thread: - main owns portmidi - main sets active = true: ownership transfers to callback - main sets active = false: main requests ownership - callback sees active == false, yields ownership back to main - main waits 2ms to make sure callback has a chance to yield - (stop making PortMidi calls), then assumes it can close - PortMidi - */ - -/* timer_poll -- the timer callback function */ -/* - * All MIDI sends take place here - */ -void timer_poll(PtTimestamp timestamp, void *userData) -{ - static int callback_owns_portmidi = false; - static PmTimestamp clock_start_time = 0; - static double next_clock_time = 0; - /* SMPTE time */ - static int frames = 0; - static int seconds = 0; - static int minutes = 0; - static int hours = 0; - static int mtc_count = 0; /* where are we in quarter frame sequence? */ - static int smpte_start_time = 0; - static double next_smpte_time = 0; - #define QUARTER_FRAME_PERIOD (1.0 / 120.0) /* 30fps, 1/4 frame */ - - if (callback_owns_portmidi && !active) { - /* main is requesting (by setting active to false) that we shut down */ - callback_owns_portmidi = false; - return; - } - if (!active) return; /* main still getting ready or it's closing down */ - callback_owns_portmidi = true; /* main is ready, we have portmidi */ - if (send_start_stop) { - if (clock_running) { - Pm_WriteShort(midi, 0, MIDI_STOP); - } else { - Pm_WriteShort(midi, 0, MIDI_START); - clock_start_time = timestamp; - next_clock_time = TEMPO_TO_CLOCK / tempo; - } - clock_running = !clock_running; - send_start_stop = false; /* until main sets it again */ - /* note that there's a slight race condition here: main could - set send_start_stop asynchronously, but we assume user is - typing slower than the clock rate */ - } - if (clock_running) { - if ((timestamp - clock_start_time) > next_clock_time) { - Pm_WriteShort(midi, 0, MIDI_TIME_CLOCK); - next_clock_time += TEMPO_TO_CLOCK / tempo; - } - } - if (time_code_running) { - int data = 0; // initialization avoids compiler warning - if ((timestamp - smpte_start_time) < next_smpte_time) - return; - switch (mtc_count) { - case 0: /* frames low nibble */ - data = frames; - break; - case 1: /* frames high nibble */ - data = frames >> 4; - break; - case 2: /* frames seconds low nibble */ - data = seconds; - break; - case 3: /* frames seconds high nibble */ - data = seconds >> 4; - break; - case 4: /* frames minutes low nibble */ - data = minutes; - break; - case 5: /* frames minutes high nibble */ - data = minutes >> 4; - break; - case 6: /* hours low nibble */ - data = hours; - break; - case 7: /* hours high nibble */ - data = hours >> 4; - break; - } - data &= 0xF; /* take only 4 bits */ - Pm_WriteShort(midi, 0, - Pm_Message(MIDI_Q_FRAME, (mtc_count << 4) + data, 0)); - mtc_count = (mtc_count + 1) & 7; /* wrap around */ - if (mtc_count == 0) { /* update time by two frames */ - frames += 2; - if (frames >= 30) { - frames = 0; - seconds++; - if (seconds >= 60) { - seconds = 0; - minutes++; - if (minutes >= 60) { - minutes = 0; - hours++; - /* just let hours wrap if it gets that far */ - } - } - } - } - next_smpte_time += QUARTER_FRAME_PERIOD; - } else { /* time_code_running is false */ - smpte_start_time = timestamp; - /* so that when it finally starts, we'll be in sync */ - } -} - - -/* read a number from console */ -/**/ -int get_number(const char *prompt) -{ - int n = 0, i; - fputs(prompt, stdout); - while (n != 1) { - n = scanf("%d", &i); - while (getchar() != '\n') ; - } - return i; -} - -/**************************************************************************** -* showhelp -* Effect: print help text -****************************************************************************/ - -private void showhelp() -{ - printf("\n"); - printf("t toggles sending MIDI Time Code (MTC)\n"); - printf("c toggles sending MIDI CLOCK (initially on)\n"); - printf("m to set tempo (from 1bpm to 300bpm)\n"); - printf("q quits\n"); - printf("\n"); -} - -/**************************************************************************** -* doascii -* Inputs: -* char c: input character -* Effect: interpret to control output -****************************************************************************/ - -private void doascii(char c) -{ - if (isupper(c)) c = tolower(c); - if (c == 'q') done = true; - else if (c == 'c') { - printf("%s MIDI CLOCKs\n", (clock_running ? "Stopping" : "Starting")); - send_start_stop = true; - } else if (c == 't') { - printf("%s MIDI Time Code\n", - (time_code_running ? "Stopping" : "Starting")); - time_code_running = !time_code_running; - } else if (c == 'm') { - int input_tempo = get_number("Enter new tempo (bpm): "); - if (input_tempo >= 1 && input_tempo <= 300) { - printf("Changing tempo to %d\n", input_tempo); - tempo = (float) input_tempo; - } else { - printf("Tempo range is 1 to 300, current tempo is %g bpm\n", - tempo); - } - } else { - showhelp(); - } -} - - -/* main - prompt for parameters, start processing */ -/* - * Prompt user to type return. - * Then send START and MIDI CLOCK for 60 beats/min. - * Commands: - * t - toggle sending MIDI Time Code (MTC) - * c - toggle sending MIDI CLOCK - * m - set tempo - * q - quit - */ -int main(int argc, char **argv) -{ - int outp; - PmError err; - int i; - if (argc > 1) { - printf("Warning: command line arguments ignored\n"); - } - showhelp(); - /* use porttime callback to send midi */ - Pt_Start(1, timer_poll, 0); - /* list device information */ - printf("MIDI output devices:\n"); - for (i = 0; i < Pm_CountDevices(); i++) { - const PmDeviceInfo *info = Pm_GetDeviceInfo(i); - if (info->output) printf("%d: %s, %s\n", i, info->interf, info->name); - } - outp = get_number("Type output device number: "); - err = Pm_OpenOutput(&midi, outp, DRIVER_INFO, OUTPUT_BUFFER_SIZE, - TIME_PROC, TIME_INFO, LATENCY); - if (err) { - puts(Pm_GetErrorText(err)); - goto error_exit_no_device; - } - active = true; - - printf("Type ENTER to start MIDI CLOCK:\n"); - while (getchar() != '\n') ; - send_start_stop = true; /* send START and then CLOCKs */ - - while (!done) { - doascii(getchar()); - while (getchar() != '\n') ; - } - - active = false; - Pt_Sleep(2); /* this is to allow callback to complete -- it's - real time, so it's either ok and it runs on - time, or there's no point to synchronizing - with it */ - /* now we "own" portmidi again */ - Pm_Close(midi); - error_exit_no_device: - Pt_Stop(); - Pm_Terminate(); - exit(0); -} - |
