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"
34 #include "scripting.h"
51 static const char *short_options
= "i:c:"
55 "e:s:t:b:d:D:N:o:nmhpP";
57 static struct option long_options
[] = {
62 {"instrument", 1, 0, 'i'},
64 {"effect", 1, 0, 'e'},
65 {"config", 1, 0, 'c'},
66 {"metronome", 0, 0, 'm'},
69 {"drum-pattern", 1, 0, 'd'},
70 {"drum-track", 1, 0, 'D'},
72 {"run-script", 1, 0, 'r'},
74 {"output", 1, 0, 'o'},
78 void print_help(char *progname
)
80 printf("Usage: %s [options]\n"
83 " -h | --help Show this help text\n"
84 " -m | --metronome Create a simple metronome pattern\n"
85 " -n | --no-ui Do not start the user interface\n"
86 " -p | --play Start pattern playback (default for -d/-D)\n"
87 " -P | --no-play Don't start pattern playback\n"
88 " -N | --no-io <rate> Use off-line processing instead of JACK I/O\n"
89 " -d | --drum-pattern <p> Load drum pattern with a given name\n"
90 " -D | --drum-track <t> Load drum track with a given name\n"
91 " -t | --tempo <bpm> Use given tempo (specified in beats/min)\n"
92 " -b | --beats <bpb> Use given beats/bar\n"
93 " -e | --effect <e> Override master effect with preset <e>\n"
94 " -i | --instrument <i> Load instrument <i> as a single-instrument scene\n"
95 " -s | --scene <s> Load a scene <s>\n"
96 " -c | --config <c> Use specified config file instead of default\n"
98 " -r | --run-script <s> Run a Python script from a given file\n"
100 " -o | --output <o> Write the first stereo output to a WAV file\n"
106 static int (*old_menu_on_idle
)(struct cbox_ui_page
*page
);
108 static int on_idle_with_ui_poll(struct cbox_ui_page
*page
)
110 cbox_app_on_idle(NULL
, NULL
);
112 if (old_menu_on_idle
)
113 return old_menu_on_idle(page
);
120 struct cbox_menu_state
*st
= NULL
;
121 struct cbox_menu_page
*page
= cbox_menu_page_new();
123 old_menu_on_idle
= page
->page
.on_idle
;
124 page
->page
.on_idle
= on_idle_with_ui_poll
;
126 struct cbox_menu
*main_menu
= create_main_menu();
128 st
= cbox_menu_state_new(page
, main_menu
, stdscr
, NULL
);
131 cbox_ui_run(&page
->page
);
133 cbox_menu_state_destroy(st
);
134 cbox_menu_page_destroy(page
);
135 cbox_menu_destroy(main_menu
);
138 int main(int argc
, char *argv
[])
140 struct cbox_open_params params
;
141 struct cbox_layer
*layer
;
142 const char *config_name
= NULL
;
143 const char *instrument_name
= NULL
;
144 const char *scene_name
= NULL
;
145 const char *effect_preset_name
= NULL
;
146 const char *drum_pattern_name
= NULL
;
147 const char *drum_track_name
= NULL
;
149 const char *script_name
= NULL
;
151 const char *output_name
= NULL
;
152 char *instr_section
= NULL
;
153 struct cbox_scene
*scene
= NULL
;
157 GError
*error
= NULL
;
158 gboolean no_ui
= FALSE
;
159 gboolean no_io
= FALSE
;
160 int play_immediately
= 0;
168 int c
= getopt_long(argc
, argv
, short_options
, long_options
, &option_index
);
174 config_name
= optarg
;
177 instrument_name
= optarg
;
180 output_name
= optarg
;
186 effect_preset_name
= optarg
;
189 drum_pattern_name
= optarg
;
192 drum_track_name
= optarg
;
196 script_name
= optarg
;
207 no_io_srate
= atoi(optarg
);
210 play_immediately
= 1;
213 play_immediately
= -1;
219 tempo
= atof(optarg
);
228 app
.document
= cbox_document_new();
229 app
.rt
= cbox_rt_new(app
.document
);
230 app
.engine
= cbox_engine_new(app
.document
, app
.rt
);
231 app
.rt
->engine
= app
.engine
;
233 cbox_config_init(config_name
);
235 tempo
= cbox_config_get_float("master", "tempo", 120);
237 bpb
= cbox_config_get_int("master", "beats_per_bar", 4);
241 cbox_rt_set_offline(app
.rt
, no_io_srate
, 1024);
245 GError
*error
= NULL
;
246 if (!cbox_io_init(&app
.io
, ¶ms
, NULL
, &error
))
248 fprintf(stderr
, "Cannot initialise sound I/O: %s\n", (error
&& error
->message
) ? error
->message
: "Unknown error");
251 cbox_rt_set_io(app
.rt
, &app
.io
);
253 cbox_wavebank_init();
255 if (!scene_name
&& !instrument_name
)
257 scene_name
= cbox_config_get_string("init", "scene");
258 instrument_name
= cbox_config_get_string("init", "instrument");
259 if (!scene_name
&& !instrument_name
)
261 if (cbox_config_has_section("scene:default"))
262 scene_name
= "default";
264 if (cbox_config_has_section("instrument:default"))
265 instrument_name
= "default";
269 scene
= cbox_scene_new(app
.document
, app
.engine
);
274 app
.current_scene_name
= g_strdup_printf("scene:%s", scene_name
);
275 if (!cbox_scene_load(scene
, scene_name
, &error
))
281 app
.current_scene_name
= g_strdup_printf("instrument:%s", instrument_name
);
282 layer
= cbox_layer_new_with_instrument(scene
, instrument_name
, &error
);
286 if (!cbox_scene_add_layer(scene
, layer
, &error
))
290 if (!effect_preset_name
)
291 effect_preset_name
= cbox_config_get_string("master", "effect");
293 if (effect_preset_name
&& *effect_preset_name
)
295 app
.engine
->effect
= cbox_module_new_from_fx_preset(effect_preset_name
, app
.document
, app
.rt
, app
.engine
, &error
);
296 if (!app
.engine
->effect
)
299 cbox_master_set_tempo(app
.engine
->master
, tempo
);
300 cbox_master_set_timesig(app
.engine
->master
, bpb
, 4);
302 if (output_name
&& scene
)
304 GError
*error
= NULL
;
305 if (!cbox_recording_source_attach(&scene
->rec_stereo_outputs
[0], cbox_recorder_new_stream(app
.engine
, app
.rt
, output_name
), &error
))
306 cbox_print_error(error
);
308 cbox_rt_start(app
.rt
, NULL
);
309 if (drum_pattern_name
)
310 cbox_song_use_looped_pattern(app
.engine
->master
->song
, cbox_midi_pattern_load(app
.engine
->master
->song
, drum_pattern_name
, 1));
311 else if (drum_track_name
)
312 cbox_song_use_looped_pattern(app
.engine
->master
->song
, cbox_midi_pattern_load_track(app
.engine
->master
->song
, drum_track_name
, 1));
314 cbox_song_use_looped_pattern(app
.engine
->master
->song
, cbox_midi_pattern_new_metronome(app
.engine
->master
->song
, app
.engine
->master
->timesig_nom
));
316 gboolean has_song
= drum_pattern_name
|| drum_track_name
|| metronome
;
317 if (play_immediately
== 1 || (play_immediately
!= -1 && has_song
))
318 cbox_master_play(app
.engine
->master
);
321 cbox_script_run(script_name
);
328 printf("Ready. Press ENTER to exit.\n");
329 fcntl(0, F_SETFL
, fcntl(0, F_GETFL
, 0) | O_NONBLOCK
);
332 if (ch
== 10 || (ch
== -1 && errno
!= EWOULDBLOCK
))
335 cbox_app_on_idle(NULL
, NULL
);
337 fcntl(0, F_SETFL
, fcntl(0, F_GETFL
, 0) &~ O_NONBLOCK
);
339 cbox_rt_stop(app
.rt
);
341 cbox_io_close(&app
.io
);
345 fprintf(stderr
, "Cannot start: %s\n", error
? error
->message
: "unknown error");
349 if (app
.engine
->effect
)
351 CBOX_DELETE(app
.engine
->effect
);
352 app
.engine
->effect
= NULL
;
354 CBOX_DELETE(app
.engine
);
357 if (cbox_wavebank_get_maxbytes() > 0)
358 g_message("Max waveform usage: %f MB", (float)(cbox_wavebank_get_maxbytes() / 1048576.0));
360 cbox_document_destroy(app
.document
);
361 cbox_wavebank_close();
364 g_free(instr_section
);