static int portaudio_start_playing () { playback_frame = seconds_to_nframes (get_playback_time ()); return 0; }
static void process_midi_output(jack_nframes_t nframes) { int i, t, bytes_remaining, track_number; unsigned char *buffer, tmp_status; void *port_buffers[MAX_NUMBER_OF_TRACKS]; jack_nframes_t last_frame_time; jack_transport_state_t transport_state; static jack_transport_state_t previous_transport_state = JackTransportStopped; static int previous_playback_started = -1; static int previous_playback_paused = 0; for (i = 0; i <= smf->number_of_tracks; i++) { port_buffers[i] = jack_port_get_buffer(output_ports[i], nframes); if (port_buffers[i] == NULL) { warn_from_jack_thread_context("jack_port_get_buffer failed, cannot send anything."); return; } #ifdef JACK_MIDI_NEEDS_NFRAMES jack_midi_clear_buffer(port_buffers[i], nframes); #else jack_midi_clear_buffer(port_buffers[i]); #endif if (just_one_output) break; } if (ctrl_c_pressed) { send_all_sound_off(port_buffers, nframes); /* The idea here is to exit at the second time process_midi_output gets called. Otherwise, All Sound Off won't be delivered. */ ctrl_c_pressed++; if (ctrl_c_pressed >= 3) exit(0); return; } // g_debug("PROCESS CALLBACK!!!"); if (playback_paused) { if (!previous_playback_paused) { send_all_sound_off(port_buffers, nframes); } previous_playback_paused = playback_paused; return; } previous_playback_paused = playback_paused; if (use_transport) { // if (!ready_to_roll) return; transport_state = jack_transport_query(jack_client, NULL); if (transport_state == JackTransportStopped) { if (previous_transport_state == JackTransportRolling) { send_all_sound_off(port_buffers, nframes); } playback_started = -1; } if (transport_state == JackTransportStarting) { playback_started = -1; } if (transport_state == JackTransportRolling) { if (previous_transport_state != JackTransportRolling) { jack_position_t position; jack_transport_query(jack_client, &position); song_position = position.frame; playback_started = jack_last_frame_time(jack_client); } } previous_transport_state = transport_state; } else { if (playback_started == -1) { if (previous_playback_started >= 0) { send_all_sound_off(port_buffers, nframes); send_sond_end(); } } previous_playback_started = playback_started; } /* End of song already? */ if (playback_started < 0) return; last_frame_time = jack_last_frame_time(jack_client); /* We may push at most one byte per 0.32ms to stay below 31.25 Kbaud limit. */ bytes_remaining = nframes_to_ms(nframes) * rate_limit; double loop_offset = loop_song(smf); for (;;) { smf_event_t *event = smf_peek_next_event(smf); int end_of_song = 0; int is_meta_event = 0; if (event == NULL) { end_of_song = 1; } else if (smf_event_is_metadata(event)) { is_meta_event = 1; char *decoded = smf_event_decode(event); if (decoded) { if (!be_quiet) g_debug("Metadata: %s", decoded); end_of_song = process_meta_event(decoded); free(decoded); } } if (end_of_song) { if (!be_quiet) g_debug("End of song."); playback_started = -1; if (!use_transport) ctrl_c_pressed = 1; break; } if (is_meta_event) { smf_event_t *ret = smf_get_next_event(smf); assert(ret != 0); continue; } bytes_remaining -= event->midi_buffer_length; if (rate_limit > 0.0 && bytes_remaining <= 0) { warn_from_jack_thread_context("Rate limiting in effect."); break; } // t = seconds_to_nframes(event->time_seconds) + playback_started - song_position + nframes - last_frame_time; t = seconds_to_nframes(event->time_seconds + loop_offset) + playback_started - song_position - last_frame_time; /* If computed time is too much into the future, we'll need to send it later. */ if (t >= (int)nframes) break; /* If computed time is < 0, we missed a cycle because of xrun. */ if (t < 0) t = 0; assert(event->track->track_number >= 0 && event->track->track_number <= MAX_NUMBER_OF_TRACKS); /* We will send this event; remove it from the queue. */ smf_event_t *ret = smf_get_next_event(smf); assert(ret != 0); /* First, send it via midi_out. */ track_number = 0; #ifdef JACK_MIDI_NEEDS_NFRAMES buffer = jack_midi_event_reserve(port_buffers[track_number], t, event->midi_buffer_length, nframes); #else buffer = jack_midi_event_reserve(port_buffers[track_number], t, event->midi_buffer_length); #endif if (buffer == NULL) { warn_from_jack_thread_context("jack_midi_event_reserve failed, NOTE LOST."); break; } memcpy(buffer, event->midi_buffer, event->midi_buffer_length); /* Ignore per-track outputs? */ if (just_one_output) continue; /* Send it via proper output port. */ track_number = event->track->track_number; #ifdef JACK_MIDI_NEEDS_NFRAMES buffer = jack_midi_event_reserve(port_buffers[track_number], t, event->midi_buffer_length, nframes); #else buffer = jack_midi_event_reserve(port_buffers[track_number], t, event->midi_buffer_length); #endif if (buffer == NULL) { warn_from_jack_thread_context("jack_midi_event_reserve failed, NOTE LOST."); break; } /* Before sending, reset channel to 0. XXX: Not very pretty. */ assert(event->midi_buffer_length >= 1); tmp_status = event->midi_buffer[0]; if (event->midi_buffer[0] >= 0x80 && event->midi_buffer[0] <= 0xEF) event->midi_buffer[0] &= 0xF0; memcpy(buffer, event->midi_buffer, event->midi_buffer_length); event->midi_buffer[0] = tmp_status; } }