2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2011 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 static gboolean
master_process_cmd(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, struct cbox_osc_command
*cmd
, GError
**error
)
29 struct cbox_master
*m
= ct
->user_data
;
30 if (!strcmp(cmd
->command
, "/status") && !*cmd
->arg_types
)
32 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
34 if (!cbox_execute_on(fb
, NULL
, "/sample_rate", "i", error
, m
->srate
))
38 return cbox_execute_on(fb
, NULL
, "/tempo", "f", error
, m
->tempo
) &&
39 cbox_execute_on(fb
, NULL
, "/timesig", "ii", error
, m
->timesig_nom
, m
->timesig_denom
) &&
40 cbox_execute_on(fb
, NULL
, "/playing", "i", error
, (int)m
->state
) &&
41 cbox_execute_on(fb
, NULL
, "/pos", "i", error
, m
->spb
->song_pos_samples
) &&
42 cbox_execute_on(fb
, NULL
, "/pos_ppqn", "i", error
, m
->spb
->song_pos_ppqn
) &&
43 cbox_execute_on(fb
, NULL
, "/ppqn_factor", "i", error
, (int)m
->ppqn_factor
);
46 if (!strcmp(cmd
->command
, "/tell") && !*cmd
->arg_types
)
48 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
52 return cbox_execute_on(fb
, NULL
, "/playing", "i", error
, (int)m
->state
) &&
53 cbox_execute_on(fb
, NULL
, "/pos", "i", error
, m
->spb
->song_pos_samples
) &&
54 cbox_execute_on(fb
, NULL
, "/pos_ppqn", "i", error
, m
->spb
->song_pos_ppqn
);
57 if (!strcmp(cmd
->command
, "/set_tempo") && !strcmp(cmd
->arg_types
, "f"))
59 cbox_master_set_tempo(m
, CBOX_ARG_F(cmd
, 0));
63 if (!strcmp(cmd
->command
, "/set_timesig") && !strcmp(cmd
->arg_types
, "ii"))
65 cbox_master_set_timesig(m
, CBOX_ARG_I(cmd
, 0), CBOX_ARG_I(cmd
, 1));
69 if (!strcmp(cmd
->command
, "/set_ppqn_factor") && !strcmp(cmd
->arg_types
, "i"))
71 m
->ppqn_factor
= CBOX_ARG_I(cmd
, 0);
75 if (!strcmp(cmd
->command
, "/play") && !strcmp(cmd
->arg_types
, ""))
81 if (!strcmp(cmd
->command
, "/stop") && !strcmp(cmd
->arg_types
, ""))
87 if (!strcmp(cmd
->command
, "/panic") && !strcmp(cmd
->arg_types
, ""))
93 if (!strcmp(cmd
->command
, "/seek_samples") && !strcmp(cmd
->arg_types
, "i"))
95 cbox_master_seek_samples(m
, CBOX_ARG_I(cmd
, 0));
99 if (!strcmp(cmd
->command
, "/seek_ppqn") && !strcmp(cmd
->arg_types
, "i"))
101 cbox_master_seek_ppqn(m
, CBOX_ARG_I(cmd
, 0));
105 if ((!strcmp(cmd
->command
, "/samples_to_ppqn") || !strcmp(cmd
->command
, "/ppqn_to_samples")) &&
106 !strcmp(cmd
->arg_types
, "i"))
108 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
112 if (cmd
->command
[1] == 's')
113 return cbox_execute_on(fb
, NULL
, "/value", "i", error
, cbox_master_samples_to_ppqn(m
, CBOX_ARG_I(cmd
, 0)));
115 return cbox_execute_on(fb
, NULL
, "/value", "i", error
, cbox_master_ppqn_to_samples(m
, CBOX_ARG_I(cmd
, 0)));
119 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Song playback not initialised.");
125 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Unknown combination of target path and argument: '%s', '%s'", cmd
->command
, cmd
->arg_types
);
130 static void cbox_master_init(struct cbox_master
*master
, struct cbox_engine
*engine
)
132 master
->srate
= engine
->io_env
.srate
;
133 master
->tempo
= 120.0;
134 master
->new_tempo
= 120.0;
135 master
->timesig_nom
= 4;
136 master
->timesig_denom
= 4;
137 master
->state
= CMTS_STOP
;
138 master
->engine
= engine
;
141 master
->ppqn_factor
= 48;
142 cbox_command_target_init(&master
->cmd_target
, master_process_cmd
, master
);
145 struct cbox_master
*cbox_master_new(struct cbox_engine
*engine
)
147 struct cbox_master
*master
= malloc(sizeof(struct cbox_master
));
148 cbox_master_init(master
, engine
);
153 void cbox_master_set_sample_rate(struct cbox_master
*master
, int srate
)
155 master
->srate
= srate
;
158 void cbox_master_set_tempo(struct cbox_master
*master
, float tempo
)
160 // XXXKF not realtime-safe; won't crash, but may lose tempo
161 // changes when used multiple times in rapid succession
162 master
->new_tempo
= tempo
;
165 void cbox_master_set_timesig(struct cbox_master
*master
, int beats
, int unit
)
167 master
->timesig_nom
= beats
;
168 master
->timesig_denom
= unit
;
171 #define cbox_master_play_args(ARG)
173 DEFINE_RT_VOID_FUNC(cbox_master
, master
, cbox_master_play
)
175 struct cbox_rt
*rt
= master
->engine
->rt
;
176 if (rt
&& rt
->io
&& rt
->io
->impl
->controltransportfunc
)
178 rt
->io
->impl
->controltransportfunc(rt
->io
->impl
, TRUE
, master
->spb
? master
->spb
->song_pos_samples
: (uint32_t)-1);
179 if (!rt
->io
->impl
->getsynccompletedfunc(rt
->io
->impl
))
180 RT_CALL_AGAIN_LATER();
183 // wait for the notes to be released
184 if (master
->state
== CMTS_STOPPING
)
186 RT_CALL_AGAIN_LATER();
190 master
->state
= CMTS_ROLLING
;
193 #define cbox_master_stop_args(ARG)
195 DEFINE_RT_VOID_FUNC(cbox_master
, master
, cbox_master_stop
)
197 struct cbox_rt
*rt
= master
->engine
->rt
;
198 if (rt
&& rt
->io
&& rt
->io
->impl
->controltransportfunc
)
200 rt
->io
->impl
->controltransportfunc(rt
->io
->impl
, FALSE
, -1);
203 if (master
->state
== CMTS_ROLLING
)
204 master
->state
= CMTS_STOPPING
;
206 if (master
->state
!= CMTS_STOP
)
207 RT_CALL_AGAIN_LATER();
210 struct seek_command_arg
212 struct cbox_master
*master
;
215 gboolean was_rolling
;
216 gboolean status_known
;
217 gboolean seek_in_progress
;
220 static int seek_transport_execute(void *arg_
)
222 struct seek_command_arg
*arg
= arg_
;
224 struct cbox_rt
*rt
= arg
->master
->engine
->rt
;
225 if (rt
&& rt
->io
&& rt
->io
->impl
->controltransportfunc
)
227 if (!arg
->seek_in_progress
)
229 arg
->seek_in_progress
= TRUE
;
230 uint32_t pos
= arg
->target_pos
;
232 arg
->target_pos
= pos
= cbox_master_ppqn_to_samples(arg
->master
, pos
);
234 rt
->io
->impl
->controltransportfunc(rt
->io
->impl
, arg
->master
->state
== CMTS_ROLLING
, pos
);
235 // JACK slow-sync won't be performed if unless transport is rolling
236 if (!arg
->was_rolling
)
238 if (arg
->master
->spb
)
239 cbox_song_playback_seek_samples(arg
->master
->spb
, arg
->target_pos
);
243 if (rt
->io
->impl
->getsynccompletedfunc(rt
->io
->impl
))
245 if (arg
->master
->spb
)
246 cbox_song_playback_seek_samples(arg
->master
->spb
, arg
->target_pos
);
252 // On first pass, check if transport is rolling from the DSP thread
253 if (!arg
->status_known
)
255 arg
->status_known
= TRUE
;
256 arg
->was_rolling
= arg
->master
->state
== CMTS_ROLLING
;
258 // If transport was rolling, stop, release notes, seek, then restart
259 if (arg
->master
->state
== CMTS_ROLLING
)
260 arg
->master
->state
= CMTS_STOPPING
;
262 // wait until transport stopped
263 if (arg
->master
->state
!= CMTS_STOP
)
266 if (arg
->master
->spb
)
269 cbox_song_playback_seek_ppqn(arg
->master
->spb
, arg
->target_pos
, FALSE
);
271 cbox_song_playback_seek_samples(arg
->master
->spb
, arg
->target_pos
);
273 if (arg
->was_rolling
)
274 arg
->master
->state
= CMTS_ROLLING
;
278 void cbox_master_seek_ppqn(struct cbox_master
*master
, uint32_t pos_ppqn
)
280 static struct cbox_rt_cmd_definition cmd
= { NULL
, seek_transport_execute
, NULL
};
281 struct seek_command_arg arg
= { master
, TRUE
, pos_ppqn
, FALSE
, FALSE
, FALSE
};
282 cbox_rt_execute_cmd_sync(master
->engine
->rt
, &cmd
, &arg
);
285 void cbox_master_seek_samples(struct cbox_master
*master
, uint32_t pos_samples
)
287 static struct cbox_rt_cmd_definition cmd
= { NULL
, seek_transport_execute
, NULL
};
288 struct seek_command_arg arg
= { master
, FALSE
, pos_samples
, FALSE
, FALSE
, FALSE
};
289 cbox_rt_execute_cmd_sync(master
->engine
->rt
, &cmd
, &arg
);
292 void cbox_master_panic(struct cbox_master
*master
)
294 cbox_master_stop(master
);
295 struct cbox_midi_buffer buf
;
296 cbox_midi_buffer_init(&buf
);
297 for (int ch
= 0; ch
< 16; ch
++)
299 cbox_midi_buffer_write_inline(&buf
, ch
, 0xB0 + ch
, 120, 0);
300 cbox_midi_buffer_write_inline(&buf
, ch
, 0xB0 + ch
, 123, 0);
301 cbox_midi_buffer_write_inline(&buf
, ch
, 0xB0 + ch
, 121, 0);
303 // Send to all outputs
304 cbox_engine_send_events_to(master
->engine
, NULL
, &buf
);
307 int cbox_master_ppqn_to_samples(struct cbox_master
*master
, int time_ppqn
)
309 double tempo
= master
->tempo
;
313 int idx
= cbox_song_playback_tmi_from_ppqn(master
->spb
, time_ppqn
);
316 const struct cbox_tempo_map_item
*tmi
= &master
->spb
->tempo_map_items
[idx
];
318 time_ppqn
-= tmi
->time_ppqn
;
319 offset
= tmi
->time_samples
;
322 return offset
+ (int)(master
->srate
* 60.0 * time_ppqn
/ (tempo
* master
->ppqn_factor
));
325 int cbox_master_samples_to_ppqn(struct cbox_master
*master
, int time_samples
)
327 double tempo
= master
->tempo
;
331 int idx
= cbox_song_playback_tmi_from_samples(master
->spb
, time_samples
);
332 if (idx
!= -1 && idx
< master
->spb
->tempo_map_item_count
)
334 const struct cbox_tempo_map_item
*tmi
= &master
->spb
->tempo_map_items
[idx
];
336 time_samples
-= tmi
->time_samples
;
337 offset
= tmi
->time_ppqn
;
340 return offset
+ (int)(tempo
* master
->ppqn_factor
* time_samples
/ (master
->srate
* 60.0));
343 void cbox_master_destroy(struct cbox_master
*master
)
347 cbox_song_playback_destroy(master
->spb
);