Report sampler polyphony correctly.
[calfbox.git] / appmenu.c
blob6bed37552e09707813976a891677ca193bf0d3bb
1 /*
2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2013 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 "blob.h"
21 #include "config-api.h"
22 #include "engine.h"
23 #include "instr.h"
24 #include "io.h"
25 #include "layer.h"
26 #include "menu.h"
27 #include "menuitem.h"
28 #include "meter.h"
29 #include "midi.h"
30 #include "module.h"
31 #include "scene.h"
32 #include "seq.h"
33 #include "song.h"
34 #include "track.h"
35 #include "ui.h"
36 #include "wavebank.h"
38 #include <assert.h>
39 #include <glib.h>
40 #include <glob.h>
41 #include <getopt.h>
42 #include <math.h>
43 #include <ncurses.h>
44 #include <stdio.h>
45 #include <stdint.h>
46 #include <string.h>
47 #include <unistd.h>
49 int cmd_quit(struct cbox_menu_item_command *item, void *context)
51 return 1;
54 int cmd_load_scene(struct cbox_menu_item_command *item, void *context)
56 GError *error = NULL;
57 struct cbox_scene *scene = app.engine->scenes[0];
58 cbox_scene_clear(scene);
59 if (!cbox_scene_load(scene, item->item.item_context, &error))
60 cbox_print_error(error);
61 return 0;
64 int cmd_load_instrument(struct cbox_menu_item_command *item, void *context)
66 GError *error = NULL;
67 struct cbox_scene *scene = app.engine->scenes[0];
68 cbox_scene_clear(scene);
69 struct cbox_layer *layer = cbox_layer_new_with_instrument(scene, (char *)item->item.item_context, &error);
71 if (layer)
73 if (!cbox_scene_add_layer(scene, layer, &error))
74 cbox_print_error(error);
76 else
78 cbox_print_error(error);
80 return 0;
83 int cmd_load_layer(struct cbox_menu_item_command *item, void *context)
85 GError *error = NULL;
86 struct cbox_scene *scene = app.engine->scenes[0];
87 cbox_scene_clear(scene);
88 struct cbox_layer *layer = cbox_layer_new_from_config(scene, (char *)item->item.item_context, &error);
90 if (layer)
92 if (!cbox_scene_add_layer(scene, layer, &error))
93 cbox_print_error(error);
95 else
97 cbox_print_error(error);
98 CBOX_DELETE(scene);
100 return 0;
103 gchar *scene_format_value(const struct cbox_menu_item_static *item, void *context)
105 if (app.current_scene_name)
106 return strdup(app.current_scene_name);
107 else
108 return strdup("- No scene -");
111 gchar *transport_format_value(const struct cbox_menu_item_static *item, void *context)
113 // XXXKF
114 // struct cbox_bbt bbt;
115 // cbox_master_to_bbt(app.engine->master, &bbt);
116 if (app.engine->master->spb == NULL)
117 return g_strdup("N/A");
118 if (!strcmp((const char *)item->item.item_context, "pos"))
119 return g_strdup_printf("%d", (int)app.engine->master->spb->song_pos_samples);
120 else
121 return g_strdup_printf("%d", (int)app.engine->master->spb->song_pos_ppqn);
124 struct cbox_config_section_cb_data
126 struct cbox_menu *menu;
127 cbox_menu_item_execute_func func;
128 const char *prefix;
131 static void config_key_process(void *user_data, const char *key)
133 struct cbox_config_section_cb_data *data = user_data;
135 if (!strncmp(key, data->prefix, strlen(data->prefix)))
137 char *title = cbox_config_get_string(key, "title");
138 if (title)
139 cbox_menu_add_item(data->menu, cbox_menu_item_new_command(title, data->func, strdup(key + strlen(data->prefix))));
140 else
141 cbox_menu_add_item(data->menu, cbox_menu_item_new_command(key, data->func, strdup(key + strlen(data->prefix))));
145 struct cbox_menu *create_scene_menu(struct cbox_menu_item_menu *item, void *menu_context)
147 struct cbox_menu *scene_menu = cbox_menu_new();
148 struct cbox_config_section_cb_data cb = { .menu = scene_menu };
150 cbox_menu_add_item(scene_menu, cbox_menu_item_new_static("Scenes", NULL, NULL));
151 cb.prefix = "scene:";
152 cb.func = cmd_load_scene;
153 cbox_config_foreach_section(config_key_process, &cb);
154 cbox_menu_add_item(scene_menu, cbox_menu_item_new_static("Layers", NULL, NULL));
155 cb.prefix = "layer:";
156 cb.func = cmd_load_layer;
157 cbox_config_foreach_section(config_key_process, &cb);
158 cbox_menu_add_item(scene_menu, cbox_menu_item_new_static("Instruments", NULL, NULL));
159 cb.prefix = "instrument:";
160 cb.func = cmd_load_instrument;
161 cbox_config_foreach_section(config_key_process, &cb);
163 cbox_menu_add_item(scene_menu, cbox_menu_item_new_menu("OK", NULL, NULL));
165 return scene_menu;
168 ///////////////////////////////////////////////////////////////////////////////
170 static struct cbox_command_target *find_module_target(const char *type, GError **error)
172 struct cbox_scene *scene = app.engine->scenes[0];
173 for (int i = 0; i < scene->instrument_count; i++)
175 if (!strcmp(scene->instruments[i]->module->engine_name, type))
176 return &scene->instruments[i]->module->cmd_target;
178 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot find a module of type '%s'", type);
179 return NULL;
183 int cmd_stream_rewind(struct cbox_menu_item_command *item, void *context)
185 GError *error = NULL;
186 struct cbox_command_target *target = find_module_target("stream_player", &error);
187 if (target)
188 cbox_execute_on(target, NULL, "/seek", "i", &error, 0);
189 cbox_print_error_if(error);
190 return 0;
193 int cmd_stream_play(struct cbox_menu_item_command *item, void *context)
195 GError *error = NULL;
196 struct cbox_command_target *target = find_module_target("stream_player", &error);
197 if (target)
198 cbox_execute_on(target, NULL, "/play", "", &error);
199 cbox_print_error_if(error);
200 return 0;
203 int cmd_stream_stop(struct cbox_menu_item_command *item, void *context)
205 GError *error = NULL;
206 struct cbox_command_target *target = find_module_target("stream_player", &error);
207 if (target)
208 cbox_execute_on(target, NULL, "/stop", "", &error);
209 cbox_print_error_if(error);
210 return 0;
213 int cmd_stream_unload(struct cbox_menu_item_command *item, void *context)
215 GError *error = NULL;
216 struct cbox_command_target *target = find_module_target("stream_player", &error);
217 if (target)
218 cbox_execute_on(target, NULL, "/unload", "", &error);
219 cbox_print_error_if(error);
220 return 0;
223 gboolean result_parser_status(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
225 cbox_osc_command_dump(cmd);
226 return TRUE;
229 int cmd_stream_status(struct cbox_menu_item_command *item, void *context)
231 struct cbox_command_target response = { NULL, result_parser_status };
232 GError *error = NULL;
233 struct cbox_command_target *target = find_module_target("stream_player", &error);
234 if (target)
235 cbox_execute_on(target, &response, "/status", "", &error);
236 cbox_print_error_if(error);
237 return 0;
240 int cmd_stream_load(struct cbox_menu_item_command *item, void *context)
242 GError *error = NULL;
243 struct cbox_command_target *target = find_module_target("stream_player", &error);
244 if (target)
245 cbox_execute_on(target, NULL, "/load", "si", &error, (gchar *)item->item.item_context, 0);
246 cbox_print_error_if(error);
247 return 0;
250 struct cbox_menu *create_stream_menu(struct cbox_menu_item_menu *item, void *menu_context)
252 struct cbox_menu *menu = cbox_menu_new();
254 cbox_menu_add_item(menu, cbox_menu_item_new_static("Module commands", NULL, NULL));
255 cbox_menu_add_item(menu, cbox_menu_item_new_command("Play stream", cmd_stream_play, NULL));
256 cbox_menu_add_item(menu, cbox_menu_item_new_command("Stop stream", cmd_stream_stop, NULL));
257 cbox_menu_add_item(menu, cbox_menu_item_new_command("Rewind stream", cmd_stream_rewind, NULL));
258 cbox_menu_add_item(menu, cbox_menu_item_new_command("Describe stream", cmd_stream_status, NULL));
259 cbox_menu_add_item(menu, cbox_menu_item_new_command("Unload stream", cmd_stream_unload, NULL));
261 glob_t g;
262 if (glob("*.wav", GLOB_TILDE_CHECK, NULL, &g) == 0)
264 for (int i = 0; i < g.gl_pathc; i++)
266 cbox_menu_add_item(menu, cbox_menu_item_new_command(g_strdup_printf("Load: %s", g.gl_pathv[i]), cmd_stream_load, g_strdup(g.gl_pathv[i])));
270 globfree(&g);
272 cbox_menu_add_item(menu, cbox_menu_item_new_menu("OK", NULL, NULL));
274 return menu;
277 ///////////////////////////////////////////////////////////////////////////////
279 static void restart_song()
281 cbox_master_stop(app.engine->master);
282 cbox_master_seek_ppqn(app.engine->master, 0);
283 cbox_master_play(app.engine->master);
286 int cmd_pattern_none(struct cbox_menu_item_command *item, void *context)
288 cbox_song_clear(app.engine->master->song);
289 cbox_engine_update_song_playback(app.engine);
290 return 0;
293 int cmd_pattern_simple(struct cbox_menu_item_command *item, void *context)
295 cbox_song_use_looped_pattern(app.engine->master->song, cbox_midi_pattern_new_metronome(app.engine->master->song, 1, app.engine->master->ppqn_factor));
296 restart_song();
297 return 0;
300 int cmd_pattern_normal(struct cbox_menu_item_command *item, void *context)
302 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));
303 restart_song();
304 return 0;
307 int cmd_load_drumpattern(struct cbox_menu_item_command *item, void *context)
309 cbox_song_use_looped_pattern(app.engine->master->song, cbox_midi_pattern_load(app.engine->master->song, item->item.item_context, 1, app.engine->master->ppqn_factor));
310 restart_song();
311 return 0;
314 int cmd_load_drumtrack(struct cbox_menu_item_command *item, void *context)
316 cbox_song_use_looped_pattern(app.engine->master->song, cbox_midi_pattern_load_track(app.engine->master->song, item->item.item_context, 1, app.engine->master->ppqn_factor));
317 restart_song();
318 return 0;
321 int cmd_load_pattern(struct cbox_menu_item_command *item, void *context)
323 cbox_song_use_looped_pattern(app.engine->master->song, cbox_midi_pattern_load(app.engine->master->song, item->item.item_context, 0, app.engine->master->ppqn_factor));
324 restart_song();
325 return 0;
328 int cmd_load_track(struct cbox_menu_item_command *item, void *context)
330 cbox_song_use_looped_pattern(app.engine->master->song, cbox_midi_pattern_load_track(app.engine->master->song, item->item.item_context, 0, app.engine->master->ppqn_factor));
331 restart_song();
332 return 0;
335 struct cbox_menu *create_pattern_menu(struct cbox_menu_item_menu *item, void *menu_context)
337 struct cbox_menu *menu = cbox_menu_new();
338 struct cbox_config_section_cb_data cb = { .menu = menu };
340 cbox_menu_add_item(menu, cbox_menu_item_new_static("Pattern commands", NULL, NULL));
341 cbox_menu_add_item(menu, cbox_menu_item_new_command("No pattern", cmd_pattern_none, NULL));
342 cbox_menu_add_item(menu, cbox_menu_item_new_command("Simple metronome", cmd_pattern_simple, NULL));
343 cbox_menu_add_item(menu, cbox_menu_item_new_command("Normal metronome", cmd_pattern_normal, NULL));
345 cbox_menu_add_item(menu, cbox_menu_item_new_static("Drum tracks", NULL, NULL));
346 cb.prefix = "drumtrack:";
347 cb.func = cmd_load_drumtrack;
348 cbox_config_foreach_section(config_key_process, &cb);
350 cbox_menu_add_item(menu, cbox_menu_item_new_static("Melodic tracks", NULL, NULL));
351 cb.prefix = "track:";
352 cb.func = cmd_load_track;
353 cbox_config_foreach_section(config_key_process, &cb);
355 cbox_menu_add_item(menu, cbox_menu_item_new_static("Drum patterns", NULL, NULL));
356 cb.prefix = "drumpattern:";
357 cb.func = cmd_load_drumpattern;
358 cbox_config_foreach_section(config_key_process, &cb);
360 cbox_menu_add_item(menu, cbox_menu_item_new_static("Melodic patterns", NULL, NULL));
361 cb.prefix = "pattern:";
362 cb.func = cmd_load_pattern;
363 cbox_config_foreach_section(config_key_process, &cb);
365 cbox_menu_add_item(menu, cbox_menu_item_new_menu("OK", NULL, NULL));
367 return menu;
370 struct cbox_menu *create_main_menu()
372 struct cbox_menu *main_menu = cbox_menu_new();
373 cbox_menu_add_item(main_menu, cbox_menu_item_new_static("Current scene:", scene_format_value, NULL));
374 cbox_menu_add_item(main_menu, cbox_menu_item_new_dynamic_menu("Set scene", create_scene_menu, NULL));
375 cbox_menu_add_item(main_menu, cbox_menu_item_new_dynamic_menu("Module control", create_stream_menu, NULL));
376 cbox_menu_add_item(main_menu, cbox_menu_item_new_dynamic_menu("Pattern control", create_pattern_menu, NULL));
378 cbox_menu_add_item(main_menu, cbox_menu_item_new_static("Variables", NULL, NULL));
379 // cbox_menu_add_item(main_menu, cbox_menu_item_new_int("foo:", &var1, 0, 127, NULL));
380 // cbox_menu_add_item(main_menu, "bar:", menu_item_value_double, &mx_double_var2, &var2);
381 cbox_menu_add_item(main_menu, cbox_menu_item_new_static("pos:", transport_format_value, "pos"));
382 cbox_menu_add_item(main_menu, cbox_menu_item_new_static("bbt:", transport_format_value, "bbt"));
383 cbox_menu_add_item(main_menu, cbox_menu_item_new_static("Commands", NULL, NULL));
384 cbox_menu_add_item(main_menu, cbox_menu_item_new_command("Quit", cmd_quit, NULL));
385 return main_menu;