Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for midi output using ALSA #62

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions tool
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ Optional Features:
--portmidi Enable or disable hardware MIDI output support with
--no-portmidi PortMidi. Note: PortMidi has memory leaks and bugs.
Default: disabled.
--alsa Enable or disable MIDI output support with ALSA.
Default: disabled.
--mouse Enable or disable mouse features in the livecoding
--no-mouse environment.
Default: enabled.
Expand Down Expand Up @@ -86,6 +88,7 @@ stats_enabled=0
pie_enabled=0
static_enabled=0
portmidi_enabled=0
alsa_enabled=0
mouse_disabled=0
config_mode=release

Expand All @@ -101,6 +104,8 @@ while getopts c:dhsv-: opt_val; do
no-portmidi|noportmidi) portmidi_enabled=0;;
mouse) mouse_disabled=0;;
no-mouse|nomouse) mouse_disabled=1;;
alsa) alsa_enabled=1;;
no-alsa|noalsa) alsa_enabled=0;;
*)
echo "Unknown long option --$OPTARG" >&2
print_usage >&2
Expand Down Expand Up @@ -339,11 +344,11 @@ build_target() {
case $cc_id in
gcc)
if cc_vers_is_gte 4.9; then
add cc_flags -march=nehalem
add cc_flags -march=native
fi
;;
clang)
add cc_flags -march=nehalem
add cc_flags -march=native
;;
esac
;;
Expand Down Expand Up @@ -400,7 +405,12 @@ build_target() {
add cc_flags -D_POSIX_C_SOURCE=200809L
;;
esac
add libraries -lmenuw -lformw -lncursesw
add libraries -lmenuw -lformw -lncursesw -ltinfow
if [[ $portmidi_enabled = 1 && $alsa_enabled = 1 ]]; then
# TODO mensagem melhor de erro?
echo -e "You can either have alsa or portmidi enabled, but not both"
exit 1
fi
if [[ $portmidi_enabled = 1 ]]; then
add libraries -lportmidi
add cc_flags -DFEAT_PORTMIDI
Expand All @@ -411,6 +421,10 @@ build_target() {
if [[ $mouse_disabled = 1 ]]; then
add cc_flags -DFEAT_NOMOUSE
fi
if [[ $alsa_enabled = 1 ]]; then
add libraries -lasound
add cc_flags -DFEAT_ALSA
fi
;;
*)
echo -e "Unknown build target '$1'\\nValid targets: orca, cli" >&2
Expand Down
84 changes: 84 additions & 0 deletions tui_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#include <portmidi.h>
#endif

#ifdef FEAT_ALSA
#include <alsa/asoundlib.h>
#endif

#define TIME_DEBUG 0
#if TIME_DEBUG
static int spin_track_timeout = 0;
Expand Down Expand Up @@ -727,6 +731,9 @@ typedef enum {
#ifdef FEAT_PORTMIDI
Midi_mode_type_portmidi,
#endif
#ifdef FEAT_ALSA
Midi_mode_type_alsa,
#endif
} Midi_mode_type;

typedef struct {
Expand All @@ -749,19 +756,31 @@ typedef struct {
static bool portmidi_is_initialized = false;
#endif

#ifdef FEAT_ALSA
typedef struct {
Midi_mode_type type;
snd_seq_t *seq;
int port_id;
} Midi_mode_alsa;
#endif

typedef union {
Midi_mode_any any;
Midi_mode_osc_bidule osc_bidule;
#ifdef FEAT_PORTMIDI
Midi_mode_portmidi portmidi;
#endif
#ifdef FEAT_ALSA
Midi_mode_alsa alsa;
#endif
} Midi_mode;

void midi_mode_init_null(Midi_mode *mm) { mm->any.type = Midi_mode_type_null; }
void midi_mode_init_osc_bidule(Midi_mode *mm, char const *path) {
mm->osc_bidule.type = Midi_mode_type_osc_bidule;
mm->osc_bidule.path = path;
}

#ifdef FEAT_PORTMIDI
enum {
Portmidi_artificial_latency = 1,
Expand Down Expand Up @@ -842,6 +861,19 @@ static bool portmidi_find_name_of_device_id(PmDeviceID id, PmError *out_pmerror,
return true;
}
#endif

#ifdef FEAT_ALSA
static void midi_mode_init_alsa(Midi_mode *mm) {
mm->alsa.type = Midi_mode_type_alsa;
if(snd_seq_open(&mm->alsa.seq, "default", SND_SEQ_OPEN_OUTPUT, SND_SEQ_NONBLOCK)) {
midi_mode_init_null(mm);
exit(1);
}
snd_seq_set_client_name(mm->alsa.seq, "orca");
mm->alsa.port_id = snd_seq_create_simple_port(mm->alsa.seq, "orca", SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC);
}
#endif

staticni void midi_mode_deinit(Midi_mode *mm) {
switch (mm->any.type) {
case Midi_mode_type_null:
Expand All @@ -863,6 +895,11 @@ staticni void midi_mode_deinit(Midi_mode *mm) {
sleep(0);
Pm_Close(mm->portmidi.stream);
break;
#endif
#ifdef FEAT_ALSA
case Midi_mode_type_alsa:
snd_seq_close(mm->alsa.seq);
break;
#endif
}
}
Expand Down Expand Up @@ -922,7 +959,11 @@ static void ged_init(Ged *a, Usz undo_limit, Usz init_bpm, Usz init_seed) {
a->accum_secs = 0.0;
a->time_to_next_note_off = 1.0;
a->oosc_dev = NULL;
#ifdef FEAT_ALSA
midi_mode_init_alsa(&a->midi_mode);
#else
midi_mode_init_null(&a->midi_mode);
#endif
a->activity_counter = 0;
a->random_seed = init_seed;
a->drag_start_y = a->drag_start_x = 0;
Expand Down Expand Up @@ -989,6 +1030,46 @@ staticni void send_midi_3bytes(Oosc_dev *oosc_dev, Midi_mode const *midi_mode,
(void)pme;
break;
}
#endif
#ifdef FEAT_ALSA
case Midi_mode_type_alsa: {
int ignore = 0;
int type = status >> 4;
int channel = status & 0xf;
snd_seq_event_t ev;
snd_seq_ev_clear(&ev);
snd_seq_ev_set_source(&ev, midi_mode->alsa.port_id);
snd_seq_ev_set_subs(&ev);
snd_seq_ev_set_direct(&ev);
switch(status) {
case 0xfa:
ev.type = SND_SEQ_EVENT_START;
snd_seq_ev_schedule_tick(&ev, SND_SEQ_QUEUE_DIRECT, 1, 0);
break;
case 0xfc:
ev.type = SND_SEQ_EVENT_STOP;
snd_seq_ev_schedule_tick(&ev, SND_SEQ_QUEUE_DIRECT, 1, 0);
break;
case 0xf8:
ev.type = SND_SEQ_EVENT_CLOCK;
snd_seq_ev_schedule_tick(&ev, SND_SEQ_QUEUE_DIRECT, 1, 0);
break;
default:
switch(type) {
case 0x8: snd_seq_ev_set_noteoff(&ev, channel, byte1, byte2); break;
case 0x9: snd_seq_ev_set_noteon(&ev, channel, byte1, byte2); break;
case 0xb: snd_seq_ev_set_controller(&ev, channel, byte1, byte2); break;
case 0xe: snd_seq_ev_set_pitchbend(&ev, channel, (byte2<<8) | byte1); break;
default: ignore = 1;
}
}

if(!ignore) {
snd_seq_event_output(midi_mode->alsa.seq, &ev);
snd_seq_drain_output(midi_mode->alsa.seq);
} else { exit(1); }
break;
}
#endif
}
}
Expand Down Expand Up @@ -2688,6 +2769,9 @@ staticni void tui_save_prefs(Tui *t) {
Confopt_portmidi_output_device);
break;
}
#endif
#ifdef FEAT_ALSA
case Midi_mode_type_alsa: break;
#endif
}
// Add all conf items touched by user that we want to write to config file.
Expand Down