Oops, don't enable timestretching on all samples by default.
[calfbox.git] / main.c
blob424c42f76daf9ec5c581c6ecce3abf8b147e8992
1 /*
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/>.
19 #include "app.h"
20 #include "config.h"
21 #include "config-api.h"
22 #include "dom.h"
23 #include "engine.h"
24 #include "instr.h"
25 #include "io.h"
26 #include "layer.h"
27 #include "menu.h"
28 #include "menuitem.h"
29 #include "midi.h"
30 #include "module.h"
31 #include "pattern.h"
32 #include "rt.h"
33 #include "scene.h"
34 #include "scripting.h"
35 #include "song.h"
36 #include "tarfile.h"
37 #include "ui.h"
38 #include "wavebank.h"
40 #include <assert.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <glib.h>
44 #include <getopt.h>
45 #include <math.h>
46 #include <ncurses.h>
47 #include <stdio.h>
48 #include <stdint.h>
49 #include <string.h>
50 #include <unistd.h>
52 static const char *short_options = "i:c:"
53 #if USE_PYTHON
54 "r:"
55 #endif
56 "e:s:t:b:d:D:N:o:nmhpP";
58 static struct option long_options[] = {
59 {"help", 0, 0, 'h'},
60 {"no-ui", 0, 0, 'n'},
61 {"play", 0, 0, 'p'},
62 {"no-io", 1, 0, 'N'},
63 {"instrument", 1, 0, 'i'},
64 {"scene", 1, 0, 's'},
65 {"effect", 1, 0, 'e'},
66 {"config", 1, 0, 'c'},
67 {"metronome", 0, 0, 'm'},
68 {"tempo", 1, 0, 't'},
69 {"beats", 1, 0, 'b'},
70 {"drum-pattern", 1, 0, 'd'},
71 {"drum-track", 1, 0, 'D'},
72 #if USE_PYTHON
73 {"run-script", 1, 0, 'r'},
74 #endif
75 {"output", 1, 0, 'o'},
76 {0,0,0,0},
79 void print_help(char *progname)
81 printf("Usage: %s [options]\n"
82 "\n"
83 "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"
98 #if USE_PYTHON
99 " -r | --run-script <s> Run a Python script from a given file\n"
100 #endif
101 " -o | --output <o> Write the first stereo output to a WAV file\n"
102 "\n",
103 progname);
104 exit(0);
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);
115 else
116 return 0;
119 void run_ui()
121 struct cbox_menu_state *st = NULL;
122 struct cbox_menu_page *page = cbox_menu_page_new();
123 cbox_ui_start();
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);
130 page->state = st;
132 cbox_ui_run(&page->page);
133 cbox_ui_stop();
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;
149 #if USE_PYTHON
150 const char *script_name = NULL;
151 #endif
152 const char *output_name = NULL;
153 char *instr_section = NULL;
154 struct cbox_scene *scene = NULL;
155 int metronome = 0;
156 int bpb = 0;
157 float tempo = 0;
158 GError *error = NULL;
159 gboolean no_ui = FALSE;
160 gboolean no_io = FALSE;
161 int play_immediately = 0;
162 int no_io_srate = 0;
164 cbox_dom_init();
166 while(1)
168 int option_index;
169 int c = getopt_long(argc, argv, short_options, long_options, &option_index);
170 if (c == -1)
171 break;
172 switch (c)
174 case 'c':
175 config_name = optarg;
176 break;
177 case 'i':
178 instrument_name = optarg;
179 break;
180 case 'o':
181 output_name = optarg;
182 break;
183 case 's':
184 scene_name = optarg;
185 break;
186 case 'e':
187 effect_preset_name = optarg;
188 break;
189 case 'd':
190 drum_pattern_name = optarg;
191 break;
192 case 'D':
193 drum_track_name = optarg;
194 break;
195 #if USE_PYTHON
196 case 'r':
197 script_name = optarg;
198 break;
199 #endif
200 case 'm':
201 metronome = 1;
202 break;
203 case 'n':
204 no_ui = TRUE;
205 break;
206 case 'N':
207 no_io = TRUE;
208 no_io_srate = atoi(optarg);
209 break;
210 case 'p':
211 play_immediately = 1;
212 break;
213 case 'P':
214 play_immediately = -1;
215 break;
216 case 'b':
217 bpb = atoi(optarg);
218 break;
219 case 't':
220 tempo = atof(optarg);
221 break;
222 case 'h':
223 case '?':
224 print_help(argv[0]);
225 return 0;
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);
236 if (tempo < 1)
237 tempo = cbox_config_get_float("master", "tempo", 120);
238 if (bpb < 1)
239 bpb = cbox_config_get_int("master", "beats_per_bar", 4);
241 if (no_io)
243 cbox_rt_set_offline(app.rt, no_io_srate, 1024);
245 else
247 GError *error = NULL;
248 if (!cbox_io_init(&app.io, &params, NULL, &error))
250 fprintf(stderr, "Cannot initialise sound I/O: %s\n", (error && error->message) ? error->message : "Unknown error");
251 return 1;
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";
265 else
266 if (cbox_config_has_section("instrument:default"))
267 instrument_name = "default";
271 scene = cbox_scene_new(app.document, app.engine);
272 if (!scene)
273 goto fail;
274 if (scene_name)
276 app.current_scene_name = g_strdup_printf("scene:%s", scene_name);
277 if (!cbox_scene_load(scene, scene_name, &error))
278 goto fail;
280 else
281 if (instrument_name)
283 app.current_scene_name = g_strdup_printf("instrument:%s", instrument_name);
284 layer = cbox_layer_new_with_instrument(scene, instrument_name, &error);
285 if (!layer)
286 goto fail;
288 if (!cbox_scene_add_layer(scene, layer, &error))
289 goto fail;
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)
299 goto fail;
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));
315 else if (metronome)
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);
321 #if USE_PYTHON
322 if (script_name)
323 cbox_script_run(script_name);
324 else
325 #endif
326 if (!no_ui)
327 run_ui();
328 else
330 printf("Ready. Press ENTER to exit.\n");
331 fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
332 do {
333 int ch = getchar();
334 if (ch == 10 || (ch == -1 && errno != EWOULDBLOCK))
335 break;
336 usleep(100000);
337 cbox_app_on_idle(NULL, NULL);
338 } while(1);
339 fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) &~ O_NONBLOCK);
341 cbox_rt_stop(app.rt);
342 if (!no_io)
343 cbox_io_close(&app.io);
344 goto ok;
346 fail:
347 fprintf(stderr, "Cannot start: %s\n", error ? error->message : "unknown error");
349 if (error)
350 g_error_free(error);
351 if (app.engine->effect)
353 CBOX_DELETE(app.engine->effect);
354 app.engine->effect = NULL;
356 CBOX_DELETE(app.engine);
357 CBOX_DELETE(app.rt);
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();
365 cbox_config_close();
367 g_free(instr_section);
369 cbox_dom_close();
371 return 0;