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/>.
21 #include "config-api.h"
33 #include "scripting.h"
50 static const char *short_options
= "i:c:"
54 "e:s:t:b:d:D:N:o:nmhpP";
56 static struct option long_options
[] = {
61 {"instrument", 1, 0, 'i'},
63 {"effect", 1, 0, 'e'},
64 {"config", 1, 0, 'c'},
65 {"metronome", 0, 0, 'm'},
68 {"drum-pattern", 1, 0, 'd'},
69 {"drum-track", 1, 0, 'D'},
71 {"run-script", 1, 0, 'r'},
73 {"output", 1, 0, 'o'},
77 void print_help(char *progname
)
79 printf("Usage: %s [options]\n"
82 " -h | --help Show this help text\n"
83 " -m | --metronome Create a simple metronome pattern\n"
84 " -n | --no-ui Do not start the user interface\n"
85 " -p | --play Start pattern playback (default for -d/-D)\n"
86 " -P | --no-play Don't start pattern playback\n"
87 " -N | --no-io <rate> Use off-line processing instead of JACK I/O\n"
88 " -d | --drum-pattern <p> Load drum pattern with a given name\n"
89 " -D | --drum-track <t> Load drum track with a given name\n"
90 " -t | --tempo <bpm> Use given tempo (specified in beats/min)\n"
91 " -b | --beats <bpb> Use given beats/bar\n"
92 " -e | --effect <e> Override master effect with preset <e>\n"
93 " -i | --instrument <i> Load instrument <i> as a single-instrument scene\n"
94 " -s | --scene <s> Load a scene <s>\n"
95 " -c | --config <c> Use specified config file instead of default\n"
97 " -r | --run-script <s> Run a Python script from a given file\n"
99 " -o | --output <o> Write the first stereo output to a WAV file\n"
105 static int (*old_menu_on_idle
)(struct cbox_ui_page
*page
);
107 static int on_idle_with_ui_poll(struct cbox_ui_page
*page
)
109 cbox_app_on_idle(NULL
, NULL
);
111 if (old_menu_on_idle
)
112 return old_menu_on_idle(page
);
119 struct cbox_menu_state
*st
= NULL
;
120 struct cbox_menu_page
*page
= cbox_menu_page_new();
122 old_menu_on_idle
= page
->page
.on_idle
;
123 page
->page
.on_idle
= on_idle_with_ui_poll
;
125 struct cbox_menu
*main_menu
= create_main_menu();
127 st
= cbox_menu_state_new(page
, main_menu
, stdscr
, NULL
);
130 cbox_ui_run(&page
->page
);
132 cbox_menu_state_destroy(st
);
133 cbox_menu_page_destroy(page
);
134 cbox_menu_destroy(main_menu
);
137 int main(int argc
, char *argv
[])
139 struct cbox_open_params params
;
140 struct cbox_layer
*layer
;
141 const char *config_name
= NULL
;
142 const char *instrument_name
= NULL
;
143 const char *scene_name
= NULL
;
144 const char *effect_preset_name
= NULL
;
145 const char *drum_pattern_name
= NULL
;
146 const char *drum_track_name
= NULL
;
148 const char *script_name
= NULL
;
150 const char *output_name
= NULL
;
151 char *instr_section
= NULL
;
152 struct cbox_scene
*scene
= NULL
;
156 GError
*error
= NULL
;
157 gboolean no_ui
= FALSE
;
158 gboolean no_io
= FALSE
;
159 int play_immediately
= 0;
167 int c
= getopt_long(argc
, argv
, short_options
, long_options
, &option_index
);
173 config_name
= optarg
;
176 instrument_name
= optarg
;
179 output_name
= optarg
;
185 effect_preset_name
= optarg
;
188 drum_pattern_name
= optarg
;
191 drum_track_name
= optarg
;
195 script_name
= optarg
;
206 no_io_srate
= atoi(optarg
);
209 play_immediately
= 1;
212 play_immediately
= -1;
218 tempo
= atof(optarg
);
227 app
.document
= cbox_document_new();
228 app
.rt
= cbox_rt_new(app
.document
);
230 cbox_config_init(config_name
);
232 tempo
= cbox_config_get_float("master", "tempo", 120);
234 bpb
= cbox_config_get_int("master", "beats_per_bar", 4);
238 cbox_rt_set_offline(app
.rt
, no_io_srate
, 1024);
242 GError
*error
= NULL
;
243 if (!cbox_io_init(&app
.io
, ¶ms
, NULL
, &error
))
245 fprintf(stderr
, "Cannot initialise sound I/O: %s\n", (error
&& error
->message
) ? error
->message
: "Unknown error");
248 cbox_rt_set_io(app
.rt
, &app
.io
);
250 cbox_wavebank_init();
252 if (!scene_name
&& !instrument_name
)
254 scene_name
= cbox_config_get_string("init", "scene");
255 instrument_name
= cbox_config_get_string("init", "instrument");
256 if (!scene_name
&& !instrument_name
)
258 if (cbox_config_has_section("scene:default"))
259 scene_name
= "default";
261 if (cbox_config_has_section("instrument:default"))
262 instrument_name
= "default";
266 scene
= cbox_scene_new(app
.document
, app
.rt
, FALSE
);
271 app
.current_scene_name
= g_strdup_printf("scene:%s", scene_name
);
272 if (!cbox_scene_load(scene
, scene_name
, &error
))
278 app
.current_scene_name
= g_strdup_printf("instrument:%s", instrument_name
);
279 layer
= cbox_layer_new_with_instrument(scene
, instrument_name
, &error
);
283 if (!cbox_scene_add_layer(scene
, layer
, &error
))
287 if (!effect_preset_name
)
288 effect_preset_name
= cbox_config_get_string("master", "effect");
290 if (effect_preset_name
&& *effect_preset_name
)
292 app
.rt
->effect
= cbox_module_new_from_fx_preset(effect_preset_name
, app
.document
, app
.rt
, &error
);
296 cbox_master_set_tempo(app
.rt
->master
, tempo
);
297 cbox_master_set_timesig(app
.rt
->master
, bpb
, 4);
299 if (output_name
&& scene
)
301 GError
*error
= NULL
;
302 if (!cbox_recording_source_attach(&scene
->rec_stereo_outputs
[0], cbox_recorder_new_stream(app
.rt
, output_name
), &error
))
303 cbox_print_error(error
);
305 cbox_rt_start(app
.rt
, NULL
);
306 if (drum_pattern_name
)
307 cbox_song_use_looped_pattern(app
.rt
->master
->song
, cbox_midi_pattern_load(app
.rt
->master
->song
, drum_pattern_name
, 1));
308 else if (drum_track_name
)
309 cbox_song_use_looped_pattern(app
.rt
->master
->song
, cbox_midi_pattern_load_track(app
.rt
->master
->song
, drum_track_name
, 1));
311 cbox_song_use_looped_pattern(app
.rt
->master
->song
, cbox_midi_pattern_new_metronome(app
.rt
->master
->song
, app
.rt
->master
->timesig_nom
));
313 gboolean has_song
= drum_pattern_name
|| drum_track_name
|| metronome
;
314 if (play_immediately
== 1 || (play_immediately
!= -1 && has_song
))
315 cbox_master_play(app
.rt
->master
);
316 cbox_rt_set_scene(app
.rt
, scene
);
319 cbox_script_run(script_name
);
326 printf("Ready. Press ENTER to exit.\n");
327 fcntl(0, F_SETFL
, fcntl(0, F_GETFL
, 0) | O_NONBLOCK
);
330 if (ch
== 10 || (ch
== -1 && errno
!= EWOULDBLOCK
))
333 cbox_app_on_idle(NULL
, NULL
);
335 fcntl(0, F_SETFL
, fcntl(0, F_GETFL
, 0) &~ O_NONBLOCK
);
337 scene
= cbox_rt_set_scene(app
.rt
, NULL
);
338 cbox_rt_stop(app
.rt
);
340 cbox_io_close(&app
.io
);
344 fprintf(stderr
, "Cannot start: %s\n", error
? error
->message
: "unknown error");
350 CBOX_DELETE(app
.rt
->effect
);
351 app
.rt
->effect
= NULL
;
358 if (cbox_wavebank_get_maxbytes() > 0)
359 g_message("Max waveform usage: %f MB", (float)(cbox_wavebank_get_maxbytes() / 1048576.0));
361 cbox_document_destroy(app
.document
);
362 cbox_wavebank_close();
365 g_free(instr_section
);