2 * Copyright (c) 2007, 2008 Edward Tomasz NapieraĆa <trasz@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE
15 * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18 * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
20 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
21 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * This is jack-smf-player, Standard MIDI File player for JACK MIDI.
31 * For questions and comments, contact Edward Tomasz Napierala <trasz@FreeBSD.org>.
36 #include <sys/types.h>
44 #include <jack/jack.h>
45 #include <jack/midiport.h>
52 #include <lash/lash.h>
55 #define PROGRAM_NAME "jack-smf-player"
56 #define PROGRAM_VERSION PACKAGE_VERSION
58 #define MIDI_CONTROLLER 0xB0
59 #define MIDI_ALL_SOUND_OFF 120
61 #define MAX_NUMBER_OF_TRACKS 128
63 jack_port_t
*output_ports
[MAX_NUMBER_OF_TRACKS
];
64 int drop_messages
= 0;
65 jack_client_t
*jack_client
= NULL
;
66 double rate_limit
= 0;
67 int just_one_output
= 0;
68 int start_stopped
= 0;
69 int use_transport
= 1;
71 volatile int playback_started
= -1, song_position
= 0, ctrl_c_pressed
= 0;
75 lash_client_t
*lash_client
;
78 /* Will emit a warning if time between jack callbacks is longer than this. */
79 #define MAX_TIME_BETWEEN_CALLBACKS 0.1
81 /* Will emit a warning if execution of jack callback takes longer than this. */
82 #define MAX_PROCESSING_TIME 0.01
91 ret
= gettimeofday(&tv
, NULL
);
94 perror("gettimeofday");
98 seconds
= tv
.tv_sec
+ tv
.tv_usec
/ 1000000.0;
106 static double previously
= -1.0;
112 if (previously
== -1.0) {
118 delta
= now
- previously
;
121 assert(delta
>= 0.0);
127 warning_async(gpointer s
)
129 const char *str
= (const char *)s
;
137 warn_from_jack_thread_context(const char *str
)
139 g_idle_add(warning_async
, (gpointer
)str
);
143 nframes_to_ms(jack_nframes_t nframes
)
147 sr
= jack_get_sample_rate(jack_client
);
151 return (nframes
* 1000.0) / (double)sr
;
155 nframes_to_seconds(jack_nframes_t nframes
)
157 return nframes_to_ms(nframes
) / 1000.0;
160 static jack_nframes_t
161 ms_to_nframes(double ms
)
165 sr
= jack_get_sample_rate(jack_client
);
169 return ((double)sr
* ms
) / 1000.0;
172 static jack_nframes_t
173 seconds_to_nframes(double seconds
)
175 return ms_to_nframes(seconds
* 1000.0);
179 send_all_sound_off(void *port_buffers
[MAX_NUMBER_OF_TRACKS
], jack_nframes_t nframes
)
182 unsigned char *buffer
;
184 for (i
= 0; i
<= smf
->number_of_tracks
; i
++) {
185 for (channel
= 0; channel
< 16; channel
++) {
186 #ifdef JACK_MIDI_NEEDS_NFRAMES
187 buffer
= jack_midi_event_reserve(port_buffers
[i
], 0, 3, nframes
);
189 buffer
= jack_midi_event_reserve(port_buffers
[i
], 0, 3);
191 if (buffer
== NULL
) {
192 warn_from_jack_thread_context("jack_midi_event_reserve failed, cannot send All Sound Off.");
196 buffer
[0] = MIDI_CONTROLLER
| channel
;
197 buffer
[1] = MIDI_ALL_SOUND_OFF
;
207 process_midi_output(jack_nframes_t nframes
)
209 int i
, t
, bytes_remaining
, track_number
;
210 unsigned char *buffer
, tmp_status
;
211 void *port_buffers
[MAX_NUMBER_OF_TRACKS
];
212 jack_nframes_t last_frame_time
;
213 jack_transport_state_t transport_state
;
214 static jack_transport_state_t previous_transport_state
= JackTransportStopped
;
216 for (i
= 0; i
<= smf
->number_of_tracks
; i
++) {
217 port_buffers
[i
] = jack_port_get_buffer(output_ports
[i
], nframes
);
219 if (port_buffers
[i
] == NULL
) {
220 warn_from_jack_thread_context("jack_port_get_buffer failed, cannot send anything.");
224 #ifdef JACK_MIDI_NEEDS_NFRAMES
225 jack_midi_clear_buffer(port_buffers
[i
], nframes
);
227 jack_midi_clear_buffer(port_buffers
[i
]);
234 if (ctrl_c_pressed
) {
235 send_all_sound_off(port_buffers
, nframes
);
237 /* The idea here is to exit at the second time process_midi_output gets called.
238 Otherwise, All Sound Off won't be delivered. */
240 if (ctrl_c_pressed
>= 3)
247 transport_state
= jack_transport_query(jack_client
, NULL
);
248 if (transport_state
== JackTransportStopped
) {
249 if (previous_transport_state
== JackTransportRolling
)
250 send_all_sound_off(port_buffers
, nframes
);
252 previous_transport_state
= transport_state
;
257 previous_transport_state
= transport_state
;
260 last_frame_time
= jack_last_frame_time(jack_client
);
262 /* End of song already? */
263 if (playback_started
< 0)
266 /* We may push at most one byte per 0.32ms to stay below 31.25 Kbaud limit. */
267 bytes_remaining
= nframes_to_ms(nframes
) * rate_limit
;
270 smf_event_t
*event
= smf_peek_next_event(smf
);
274 g_debug("End of song.");
275 playback_started
= -1;
283 /* Skip over metadata events. */
284 if (smf_event_is_metadata(event
)) {
285 char *decoded
= smf_event_decode(event
);
286 if (decoded
&& !be_quiet
)
287 g_debug("Metadata: %s", decoded
);
289 smf_get_next_event(smf
);
293 bytes_remaining
-= event
->midi_buffer_length
;
295 if (rate_limit
> 0.0 && bytes_remaining
<= 0) {
296 warn_from_jack_thread_context("Rate limiting in effect.");
300 t
= seconds_to_nframes(event
->time_seconds
) + playback_started
- song_position
+ nframes
- last_frame_time
;
302 /* If computed time is too much into the future, we'll need
304 if (t
>= (int)nframes
)
307 /* If computed time is < 0, we missed a cycle because of xrun. */
311 assert(event
->track
->track_number
>= 0 && event
->track
->track_number
<= MAX_NUMBER_OF_TRACKS
);
313 /* We will send this event; remove it from the queue. */
314 smf_get_next_event(smf
);
316 /* First, send it via midi_out. */
319 #ifdef JACK_MIDI_NEEDS_NFRAMES
320 buffer
= jack_midi_event_reserve(port_buffers
[track_number
], t
, event
->midi_buffer_length
, nframes
);
322 buffer
= jack_midi_event_reserve(port_buffers
[track_number
], t
, event
->midi_buffer_length
);
325 if (buffer
== NULL
) {
326 warn_from_jack_thread_context("jack_midi_event_reserve failed, NOTE LOST.");
330 memcpy(buffer
, event
->midi_buffer
, event
->midi_buffer_length
);
332 /* Ignore per-track outputs? */
336 /* Send it via proper output port. */
337 track_number
= event
->track
->track_number
;
339 #ifdef JACK_MIDI_NEEDS_NFRAMES
340 buffer
= jack_midi_event_reserve(port_buffers
[track_number
], t
, event
->midi_buffer_length
, nframes
);
342 buffer
= jack_midi_event_reserve(port_buffers
[track_number
], t
, event
->midi_buffer_length
);
345 if (buffer
== NULL
) {
346 warn_from_jack_thread_context("jack_midi_event_reserve failed, NOTE LOST.");
350 /* Before sending, reset channel to 0. XXX: Not very pretty. */
351 assert(event
->midi_buffer_length
>= 1);
353 tmp_status
= event
->midi_buffer
[0];
355 if (event
->midi_buffer
[0] >= 0x80 && event
->midi_buffer
[0] <= 0xEF)
356 event
->midi_buffer
[0] &= 0xF0;
358 memcpy(buffer
, event
->midi_buffer
, event
->midi_buffer_length
);
360 event
->midi_buffer
[0] = tmp_status
;
365 process_callback(jack_nframes_t nframes
, void *notused
)
368 if (get_delta_time() > MAX_TIME_BETWEEN_CALLBACKS
) {
369 warn_from_jack_thread_context("Had to wait too long for JACK callback; scheduling problem?");
373 /* Check for impossible condition that actually happened to me, caused by some problem between jackd and OSS4. */
375 warn_from_jack_thread_context("Process callback called with nframes = 0; bug in JACK?");
379 process_midi_output(nframes
);
382 if (get_delta_time() > MAX_PROCESSING_TIME
) {
383 warn_from_jack_thread_context("Processing took too long; scheduling problem?");
391 sync_callback(jack_transport_state_t state
, jack_position_t
*position
, void *notused
)
395 /* XXX: We should probably adapt to external tempo changes. */
397 if (state
== JackTransportStarting
) {
398 song_position
= position
->frame
;
399 smf_seek_to_seconds(smf
, nframes_to_seconds(position
->frame
));
402 g_debug("Seeking to %f seconds.", nframes_to_seconds(position
->frame
));
404 playback_started
= jack_frame_time(jack_client
);
406 } else if (state
== JackTransportStopped
) {
407 playback_started
= -1;
413 void timebase_callback(jack_transport_state_t state
, jack_nframes_t nframes
, jack_position_t
*pos
, int new_pos
, void *notused
)
415 double min
; /* Minutes since frame 0. */
416 long abs_tick
; /* Ticks since frame 0. */
417 long abs_beat
; /* Beats since frame 0. */
419 static smf_tempo_t
*previous_tempo
= NULL
;
421 smf_event_t
*event
= smf_peek_next_event(smf
);
425 tempo
= smf_get_tempo_by_pulses(smf
, event
->time_pulses
);
429 if (new_pos
|| previous_tempo
!= tempo
) {
430 pos
->valid
= JackPositionBBT
;
431 pos
->beats_per_bar
= tempo
->numerator
;
432 pos
->beat_type
= 1.0 / (double)tempo
->denominator
;
433 pos
->ticks_per_beat
= event
->track
->smf
->ppqn
; /* XXX: Is this right? */
434 pos
->beats_per_minute
= 60000000.0 / (double)tempo
->microseconds_per_quarter_note
;
436 min
= pos
->frame
/ ((double) pos
->frame_rate
* 60.0);
437 abs_tick
= min
* pos
->beats_per_minute
* pos
->ticks_per_beat
;
438 abs_beat
= abs_tick
/ pos
->ticks_per_beat
;
440 pos
->bar
= abs_beat
/ pos
->beats_per_bar
;
441 pos
->beat
= abs_beat
- (pos
->bar
* pos
->beats_per_bar
) + 1;
442 pos
->tick
= abs_tick
- (abs_beat
* pos
->ticks_per_beat
);
443 pos
->bar_start_tick
= pos
->bar
* pos
->beats_per_bar
* pos
->ticks_per_beat
;
444 pos
->bar
++; /* adjust start to bar 1 */
446 previous_tempo
= tempo
;
449 /* Compute BBT info based on previous period. */
450 pos
->tick
+= nframes
* pos
->ticks_per_beat
* pos
->beats_per_minute
/ (pos
->frame_rate
* 60);
452 while (pos
->tick
>= pos
->ticks_per_beat
) {
453 pos
->tick
-= pos
->ticks_per_beat
;
454 if (++pos
->beat
> pos
->beats_per_bar
) {
457 pos
->bar_start_tick
+= pos
->beats_per_bar
* pos
->ticks_per_beat
;
463 /* Connects to the specified input port, disconnecting already connected ports. */
465 connect_to_input_port(const char *port
)
469 ret
= jack_port_disconnect(jack_client
, output_ports
[0]);
472 g_warning("Cannot disconnect MIDI port.");
477 ret
= jack_connect(jack_client
, jack_port_name(output_ports
[0]), port
);
480 g_warning("Cannot connect to %s.", port
);
485 g_warning("Connected to %s.", port
);
499 jack_client
= jack_client_open(PROGRAM_NAME
, JackNullOption
, NULL
);
501 if (jack_client
== NULL
) {
502 g_critical("Could not connect to the JACK server; run jackd first?");
503 exit(EX_UNAVAILABLE
);
507 event
= lash_event_new_with_type(LASH_Client_Name
);
508 assert (event
); /* Documentation does not say anything about return value. */
509 lash_event_set_string(event
, jack_get_client_name(jack_client
));
510 lash_send_event(lash_client
, event
);
512 lash_jack_client_name(lash_client
, jack_get_client_name(jack_client
));
515 err
= jack_set_process_callback(jack_client
, process_callback
, 0);
517 g_critical("Could not register JACK process callback.");
518 exit(EX_UNAVAILABLE
);
522 err
= jack_set_sync_callback(jack_client
, sync_callback
, 0);
524 g_critical("Could not register JACK sync callback.");
525 exit(EX_UNAVAILABLE
);
528 err
= jack_set_timebase_callback(jack_client
, 1, timebase_callback
, 0);
530 g_critical("Could not register JACK timebase callback.");
531 exit(EX_UNAVAILABLE
);
536 assert(smf
->number_of_tracks
>= 1);
538 /* We are allocating number_of_tracks + 1 output ports. */
539 for (i
= 0; i
<= smf
->number_of_tracks
; i
++) {
543 snprintf(port_name
, sizeof(port_name
), "midi_out");
545 snprintf(port_name
, sizeof(port_name
), "track_%d_midi_out", i
);
547 output_ports
[i
] = jack_port_register(jack_client
, port_name
, JACK_DEFAULT_MIDI_TYPE
, JackPortIsOutput
, 0);
549 if (output_ports
[i
] == NULL
) {
550 g_critical("Could not register JACK output port '%s'.", port_name
);
551 exit(EX_UNAVAILABLE
);
558 if (jack_activate(jack_client
)) {
559 g_critical("Cannot activate JACK client.");
560 exit(EX_UNAVAILABLE
);
567 lash_callback(gpointer notused
)
571 while ((event
= lash_get_event(lash_client
))) {
572 switch (lash_event_get_type(event
)) {
573 case LASH_Restore_Data_Set
:
574 case LASH_Save_Data_Set
:
578 g_warning("Exiting due to LASH request.");
583 g_warning("Receieved unknown LASH event of type %d.", lash_event_get_type(event
));
584 lash_event_destroy(event
);
592 init_lash(lash_args_t
*args
)
594 /* XXX: Am I doing the right thing wrt protocol version? */
595 lash_client
= lash_init(args
, PROGRAM_NAME
, LASH_Config_Data_Set
, LASH_PROTOCOL(2, 0));
597 if (!lash_server_connected(lash_client
)) {
598 g_critical("Cannot initialize LASH. Continuing anyway.");
599 /* exit(EX_UNAVAILABLE); */
604 /* Schedule a function to process LASH events, ten times per second. */
605 g_timeout_add(100, lash_callback
, NULL
);
608 #endif /* HAVE_LASH */
611 * This is neccessary for exiting due to jackd being killed, when exit(0)
612 * in process_callback won't get called for obvious reasons.
615 emergency_exit_timeout(gpointer notused
)
617 if (ctrl_c_pressed
== 0)
624 ctrl_c_handler(int signum
)
630 log_handler(const gchar
*log_domain
, GLogLevelFlags log_level
, const gchar
*message
, gpointer notused
)
632 fprintf(stderr
, "%s: %s\n", log_domain
, message
);
638 fprintf(stdout
, "%s %s, libsmf %s\n", PROGRAM_NAME
, PROGRAM_VERSION
, smf_get_version());
646 fprintf(stderr
, "usage: jack-smf-player [-dnqstV] [ -a <input port>] [-r <rate>] file_name\n");
652 main(int argc
, char *argv
[])
655 char *file_name
, *autoconnect_port_name
= NULL
;
658 lash_args_t
*lash_args
;
664 lash_args
= lash_extract_args(&argc
, &argv
);
667 g_log_set_default_handler(log_handler
, NULL
);
669 while ((ch
= getopt(argc
, argv
, "a:dnqr:stV")) != -1) {
672 autoconnect_port_name
= strdup(optarg
);
688 rate_limit
= strtod(optarg
, NULL
);
689 if (rate_limit
<= 0.0) {
690 g_critical("Invalid rate limit specified.\n");
718 if (argv
[0] == NULL
) {
719 g_critical("No file name given.");
725 smf
= smf_load(file_name
);
728 g_critical("Loading SMF file failed.");
734 g_message("%s.", smf_decode(smf
));
736 if (smf
->number_of_tracks
> MAX_NUMBER_OF_TRACKS
) {
737 g_warning("Number of tracks (%d) exceeds maximum for per-track output; implying '-s' option.", smf
->number_of_tracks
);
742 init_lash(lash_args
);
745 g_timeout_add(1000, emergency_exit_timeout
, (gpointer
)0);
746 signal(SIGINT
, ctrl_c_handler
);
750 if (autoconnect_port_name
) {
751 if (connect_to_input_port(autoconnect_port_name
)) {
752 g_critical("Couldn't connect to '%s', exiting.", autoconnect_port_name
);
753 exit(EX_UNAVAILABLE
);
757 if (use_transport
&& !start_stopped
) {
758 jack_transport_locate(jack_client
, 0);
759 jack_transport_start(jack_client
);
763 playback_started
= jack_frame_time(jack_client
);
765 g_main_loop_run(g_main_loop_new(NULL
, TRUE
));