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"
52 static const char *short_options
= "i:c:"
56 "e:s:t:b:d:D:N:o:nmhpP";
58 static struct option long_options
[] = {
63 {"instrument", 1, 0, 'i'},
65 {"effect", 1, 0, 'e'},
66 {"config", 1, 0, 'c'},
67 {"metronome", 0, 0, 'm'},
70 {"drum-pattern", 1, 0, 'd'},
71 {"drum-track", 1, 0, 'D'},
73 {"run-script", 1, 0, 'r'},
75 {"output", 1, 0, 'o'},
79 void print_help(char *progname
)
81 printf("Usage: %s [options]\n"
84 " -h | --help Show this help text\n"
85 " -m | --metronome Create a simple metronome pattern\n"
86 " -n | --no-ui Do not start the user interface\n"
87 " -p | --play Start pattern playback (default for -d/-D)\n"
88 " -P | --no-play Don't start pattern playback\n"
89 " -N | --no-io <rate> Use off-line processing instead of JACK I/O\n"
90 " -d | --drum-pattern <p> Load drum pattern with a given name\n"
91 " -D | --drum-track <t> Load drum track with a given name\n"
92 " -t | --tempo <bpm> Use given tempo (specified in beats/min)\n"
93 " -b | --beats <bpb> Use given beats/bar\n"
94 " -e | --effect <e> Override master effect with preset <e>\n"
95 " -i | --instrument <i> Load instrument <i> as a single-instrument scene\n"
96 " -s | --scene <s> Load a scene <s>\n"
97 " -c | --config <c> Use specified config file instead of default\n"
99 " -r | --run-script <s> Run a Python script from a given file\n"
101 " -o | --output <o> Write the first stereo output to a WAV file\n"
107 static int (*old_menu_on_idle
)(struct cbox_ui_page
*page
);
109 static int on_idle_with_ui_poll(struct cbox_ui_page
*page
)
111 cbox_app_on_idle(NULL
, NULL
);
113 if (old_menu_on_idle
)
114 return old_menu_on_idle(page
);
121 struct cbox_menu_state
*st
= NULL
;
122 struct cbox_menu_page
*page
= cbox_menu_page_new();
124 old_menu_on_idle
= page
->page
.on_idle
;
125 page
->page
.on_idle
= on_idle_with_ui_poll
;
127 struct cbox_menu
*main_menu
= create_main_menu();
129 st
= cbox_menu_state_new(page
, main_menu
, stdscr
, NULL
);
132 cbox_ui_run(&page
->page
);
134 cbox_menu_state_destroy(st
);
135 cbox_menu_page_destroy(page
);
136 cbox_menu_destroy(main_menu
);
139 int main(int argc
, char *argv
[])
141 struct cbox_open_params params
;
142 struct cbox_layer
*layer
;
143 const char *config_name
= NULL
;
144 const char *instrument_name
= NULL
;
145 const char *scene_name
= NULL
;
146 const char *effect_preset_name
= NULL
;
147 const char *drum_pattern_name
= NULL
;
148 const char *drum_track_name
= NULL
;
150 const char *script_name
= NULL
;
152 const char *output_name
= NULL
;
153 char *instr_section
= NULL
;
154 struct cbox_scene
*scene
= NULL
;
158 GError
*error
= NULL
;
159 gboolean no_ui
= FALSE
;
160 gboolean no_io
= FALSE
;
161 int play_immediately
= 0;
169 int c
= getopt_long(argc
, argv
, short_options
, long_options
, &option_index
);
175 config_name
= optarg
;
178 instrument_name
= optarg
;
181 output_name
= optarg
;
187 effect_preset_name
= optarg
;
190 drum_pattern_name
= optarg
;
193 drum_track_name
= optarg
;
197 script_name
= optarg
;
208 no_io_srate
= atoi(optarg
);
211 play_immediately
= 1;
214 play_immediately
= -1;
220 tempo
= atof(optarg
);
229 app
.tarpool
= cbox_tarpool_new();
230 app
.document
= cbox_document_new();
231 app
.rt
= cbox_rt_new(app
.document
);
232 app
.engine
= cbox_engine_new(app
.document
, app
.rt
);
233 app
.rt
->engine
= app
.engine
;
235 cbox_config_init(config_name
);
237 tempo
= cbox_config_get_float("master", "tempo", 120);
239 bpb
= cbox_config_get_int("master", "beats_per_bar", 4);
243 cbox_rt_set_offline(app
.rt
, no_io_srate
, 1024);
247 GError
*error
= NULL
;
248 if (!cbox_io_init(&app
.io
, ¶ms
, NULL
, &error
))
250 fprintf(stderr
, "Cannot initialise sound I/O: %s\n", (error
&& error
->message
) ? error
->message
: "Unknown error");
253 cbox_rt_set_io(app
.rt
, &app
.io
);
255 cbox_wavebank_init();
257 if (!scene_name
&& !instrument_name
)
259 scene_name
= cbox_config_get_string("init", "scene");
260 instrument_name
= cbox_config_get_string("init", "instrument");
261 if (!scene_name
&& !instrument_name
)
263 if (cbox_config_has_section("scene:default"))
264 scene_name
= "default";
266 if (cbox_config_has_section("instrument:default"))
267 instrument_name
= "default";
271 scene
= cbox_scene_new(app
.document
, app
.engine
);
276 app
.current_scene_name
= g_strdup_printf("scene:%s", scene_name
);
277 if (!cbox_scene_load(scene
, scene_name
, &error
))
283 app
.current_scene_name
= g_strdup_printf("instrument:%s", instrument_name
);
284 layer
= cbox_layer_new_with_instrument(scene
, instrument_name
, &error
);
288 if (!cbox_scene_add_layer(scene
, layer
, &error
))
292 if (!effect_preset_name
)
293 effect_preset_name
= cbox_config_get_string("master", "effect");
295 if (effect_preset_name
&& *effect_preset_name
)
297 app
.engine
->effect
= cbox_module_new_from_fx_preset(effect_preset_name
, app
.document
, app
.rt
, app
.engine
, &error
);
298 if (!app
.engine
->effect
)
301 cbox_master_set_tempo(app
.engine
->master
, tempo
);
302 cbox_master_set_timesig(app
.engine
->master
, bpb
, 4);
304 if (output_name
&& scene
)
306 GError
*error
= NULL
;
307 if (!cbox_recording_source_attach(&scene
->rec_stereo_outputs
[0], cbox_recorder_new_stream(app
.engine
, app
.rt
, output_name
), &error
))
308 cbox_print_error(error
);
310 cbox_rt_start(app
.rt
, NULL
);
311 if (drum_pattern_name
)
312 cbox_song_use_looped_pattern(app
.engine
->master
->song
, cbox_midi_pattern_load(app
.engine
->master
->song
, drum_pattern_name
, 1, app
.engine
->master
->ppqn_factor
));
313 else if (drum_track_name
)
314 cbox_song_use_looped_pattern(app
.engine
->master
->song
, cbox_midi_pattern_load_track(app
.engine
->master
->song
, drum_track_name
, 1, app
.engine
->master
->ppqn_factor
));
316 cbox_song_use_looped_pattern(app
.engine
->master
->song
, cbox_midi_pattern_new_metronome(app
.engine
->master
->song
, app
.engine
->master
->timesig_nom
, app
.engine
->master
->ppqn_factor
));
318 gboolean has_song
= drum_pattern_name
|| drum_track_name
|| metronome
;
319 if (play_immediately
== 1 || (play_immediately
!= -1 && has_song
))
320 cbox_master_play(app
.engine
->master
);
323 cbox_script_run(script_name
);
330 printf("Ready. Press ENTER to exit.\n");
331 fcntl(0, F_SETFL
, fcntl(0, F_GETFL
, 0) | O_NONBLOCK
);
334 if (ch
== 10 || (ch
== -1 && errno
!= EWOULDBLOCK
))
337 cbox_app_on_idle(NULL
, NULL
);
339 fcntl(0, F_SETFL
, fcntl(0, F_GETFL
, 0) &~ O_NONBLOCK
);
341 cbox_rt_stop(app
.rt
);
343 cbox_io_close(&app
.io
);
347 fprintf(stderr
, "Cannot start: %s\n", error
? error
->message
: "unknown error");
351 if (app
.engine
->effect
)
353 CBOX_DELETE(app
.engine
->effect
);
354 app
.engine
->effect
= NULL
;
356 CBOX_DELETE(app
.engine
);
358 cbox_tarpool_destroy(app
.tarpool
);
360 if (cbox_wavebank_get_maxbytes() > 0)
361 g_message("Max waveform usage: %f MB", (float)(cbox_wavebank_get_maxbytes() / 1048576.0));
363 cbox_document_destroy(app
.document
);
364 cbox_wavebank_close();
367 g_free(instr_section
);