diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | bin/CMakeLists.txt | 75 | ||||
-rw-r--r-- | bin/pcmi.cpp | 8 | ||||
-rw-r--r-- | bin/pcmi.h | 3 | ||||
-rw-r--r-- | bin/synthpod_alsa.c | 556 | ||||
-rw-r--r-- | bin/synthpod_bin.h | 532 | ||||
-rw-r--r-- | bin/synthpod_jack.c | 551 | ||||
-rw-r--r-- | bin/synthpod_pa.c | 653 | ||||
-rw-r--r-- | bin/synthpod_pa.desktop.in | 8 | ||||
-rw-r--r-- | bin/synthpod_rtaudio.cpp | 30 | ||||
-rw-r--r-- | bin/synthpod_rtaudio.desktop.in | 8 | ||||
-rw-r--r-- | lib/synthpod_app.c | 32 |
13 files changed, 1112 insertions, 1348 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..57006939 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +tags +*.taghl diff --git a/CMakeLists.txt b/CMakeLists.txt index b21ad20e..a987c262 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,8 +33,6 @@ set(CMAKE_CXX_FLAGS "-std=gnu++11 -ffast-math -fvisibility=hidden ${CMAKE_CXX_FL option(BUILD_UI "Build user interface libraries" ON) option(BUILD_JACK "Build JACK standalone host" ON) option(BUILD_ALSA "Build ALSA standalone host (experimental)" OFF) -option(BUILD_RTAUDIO "Build RtAudio standalone host (experimental)" OFF) -option(BUILD_PORTAUDIO "Build PortAudio standalone host (broken)" OFF) # vectorization include(CheckCCompilerFlag) diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt index c8434f70..24b50e72 100644 --- a/bin/CMakeLists.txt +++ b/bin/CMakeLists.txt @@ -11,16 +11,7 @@ set(SYNTHPOD_BIN_DIR "bin") set(SYNTHPOD_ICON_DIR "share/icons/hicolor/256x256/apps") set(SYNTHPOD_DESKTOP_DIR "share/applications") -if(APPLE) - find_library(CORE_AUDIO CoreAudio) - find_library(AUDIO_TOOLBOX AudioToolbox) - find_library(AUDIO_UNIT AudioUnit) - find_library(CARBON Carbon) - - find_library(CORE_SERVICES CoreServices) -endif(APPLE) - -if(BUILD_JACK OR BUILD_PORTAUDIO) +if(BUILD_JACK OR BUILD_ALSA) # icon install(FILES ${PROJECT_SOURCE_DIR}/data/pix/synthpod.png DESTINATION ${SYNTHPOD_ICON_DIR}) @@ -100,6 +91,7 @@ if(BUILD_ALSA) ext_urid.c) target_link_libraries(synthpod.alsa ${ECORE_CON_LDFLAGS} + "-lasound" #FIXME ${ZITA_ALSA_PCMI_LIBRARY} "-lm" synthpod.lib) @@ -116,66 +108,3 @@ if(BUILD_ALSA) install(FILES ${PROJECT_BINARY_DIR}/bin/synthpod_alsa.desktop DESTINATION ${SYNTHPOD_DESKTOP_DIR}) endif() - -if(BUILD_RTAUDIO) -# rtaudio - pkg_search_module(RTAUDIO REQUIRED librtaudio>=4.1) - include_directories(${RTAUDIO_INCLUDE_DIRS}) - -# synthpod - add_executable(synthpod.rtaudio - synthpod_rtaudio.cpp - synthpod_nsm.c - ext_urid.c) - target_link_libraries(synthpod.rtaudio - ${ECORE_CON_LDFLAGS} - ${RTAUDIO_LDFLAGS} - "-lm" - synthpod.lib) - if(BUILD_UI) - target_link_libraries(synthpod.rtaudio - synthpod_ui.lib) - endif() - set_target_properties(synthpod.rtaudio PROPERTIES OUTPUT_NAME "synthpod_rtaudio") - install(TARGETS synthpod.rtaudio DESTINATION bin) - -# desktop file - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/synthpod_rtaudio.desktop.in - ${PROJECT_BINARY_DIR}/bin/synthpod_rtaudio.desktop @ONLY) - install(FILES ${PROJECT_BINARY_DIR}/bin/synthpod_rtaudio.desktop DESTINATION - ${SYNTHPOD_DESKTOP_DIR}) -endif() - -if(BUILD_PORTAUDIO) -# portaudio - pkg_search_module(PORTAUDIO REQUIRED portaudio-2.0>=19) - include_directories(${PORTAUDIO_INCLUDE_DIRS}) - - if(APPLE) - set(PORTAUDIO_LIBS ${CORE_AUDIO} ${AUDIO_TOOLBOX} ${AUDIO_UNIT} ${CARBON} "-lportaudio") - else() - set(PORTAUDIO_LIBS ${PORTAUDIO_LDFLAGS}) - endif() - -# synthpod - add_executable(synthpod.pa - synthpod_pa.c - synthpod_nsm.c - ext_urid.c) - target_link_libraries(synthpod.pa - ${ECORE_CON_LDFLAGS} - ${PORTAUDIO_LIBS} - synthpod.lib) - if(BUILD_UI) - target_link_libraries(synthpod.pa - synthpod_ui.lib) - endif() - set_target_properties(synthpod.pa PROPERTIES OUTPUT_NAME "synthpod_pa") - install(TARGETS synthpod.pa DESTINATION bin) - -# desktop file - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/synthpod_pa.desktop.in - ${PROJECT_BINARY_DIR}/bin/synthpod_pa.desktop @ONLY) - install(FILES ${PROJECT_BINARY_DIR}/bin/synthpod_pa.desktop DESTINATION - ${SYNTHPOD_DESKTOP_DIR}) -endif() diff --git a/bin/pcmi.cpp b/bin/pcmi.cpp index 4dd43ab7..6fabd49e 100644 --- a/bin/pcmi.cpp +++ b/bin/pcmi.cpp @@ -121,6 +121,14 @@ pcmi_play_init(pcmi_t *pcmi, uint32_t frsize) } void +pcmi_clear_chan(pcmi_t *pcmi, uint32_t channel, uint32_t frsize) +{ + Alsa_pcmi *_pcmi = (Alsa_pcmi *)pcmi; + + _pcmi->clear_chan(channel, frsize); +} + +void pcmi_play_chan(pcmi_t *pcmi, uint32_t channel, const float *src, uint32_t frsize) { Alsa_pcmi *_pcmi = (Alsa_pcmi *)pcmi; @@ -61,6 +61,9 @@ void pcmi_play_init(pcmi_t *pcmi, uint32_t frsize); void +pcmi_clear_chan(pcmi_t *pcmi, uint32_t channel, uint32_t frsize); + +void pcmi_play_chan(pcmi_t *pcmi, uint32_t channel, const float *src, uint32_t frsize); void diff --git a/bin/synthpod_alsa.c b/bin/synthpod_alsa.c index 77a900d7..b9826036 100644 --- a/bin/synthpod_alsa.c +++ b/bin/synthpod_alsa.c @@ -20,28 +20,65 @@ #include <unistd.h> #include <ctype.h> +#include <asoundlib.h> #include <pcmi.h> -//#include <seq.h> -#include <Elementary.h> +#include <synthpod_bin.h> +typedef enum _chan_type_t chan_type_t; typedef struct _prog_t prog_t; +typedef struct _chan_t chan_t; + +enum _chan_type_t { + CHAN_TYPE_PCMI, + CHAN_TYPE_MIDI +}; + +struct _chan_t { + chan_type_t type; + + union { + struct { + //TODO + } audio; + struct { + int port; + snd_midi_event_t *trans; + } midi; + }; +}; struct _prog_t { + bin_t bin; + + LV2_Atom_Forge forge; + + LV2_URID midi_MidiEvent; + pcmi_t *pcmi; + snd_seq_t *seq; + int queue; + + save_state_t save_state; volatile int kill; Eina_Thread thread; uint32_t srate; uint32_t frsize; uint32_t nfrags; + int twochan; + + const char *play_name; + const char *capt_name; }; -void * +static void * _rt_thread(void *data, Eina_Thread thread) { - prog_t *prog = data; - pcmi_t *pcmi = prog->pcmi; + prog_t *handle = data; + pcmi_t *pcmi = handle->pcmi; + bin_t *bin = &handle->bin; + sp_app_t *app = bin->app; pthread_t self = pthread_self(); @@ -54,52 +91,433 @@ _rt_thread(void *data, Eina_Thread thread) if(pthread_setschedparam(self, SCHED_RR, &schedp)) fprintf(stderr, "pthread_setschedparam error\n"); } + + const uint32_t nsamples = handle->frsize; + const size_t sample_buf_size = sizeof(float) * nsamples; + int play_num; + int capt_num; + + pcmi_pcm_start(handle->pcmi); + while(!handle->kill) + { + int na = pcmi_pcm_wait(pcmi); + + while(na >= nsamples) + { + const sp_app_system_source_t *sources = sp_app_get_system_sources(app); + const sp_app_system_sink_t *sinks = sp_app_get_system_sinks(app); + + int paused = sp_app_paused(app); + if(paused == 1) // aka loading state + { + // clear output buffers + pcmi_play_init(pcmi, nsamples); + play_num = 0; + for(const sp_app_system_sink_t *sink=sinks; + sink->type != SYSTEM_PORT_NONE; + sink++) + { + switch(sink->type) + { + case SYSTEM_PORT_NONE: + case SYSTEM_PORT_CONTROL: + case SYSTEM_PORT_CV: + case SYSTEM_PORT_OSC: + break; + + case SYSTEM_PORT_AUDIO: + { + chan_t *chan = sink->sys_port; - const int nplay = pcmi_nplay(pcmi); - const int ncapt = pcmi_ncapt(pcmi); + pcmi_clear_chan(pcmi, play_num++, nsamples); - float inp [ncapt][prog->frsize]; - float out [nplay][prog->frsize]; + break; + } + + case SYSTEM_PORT_MIDI: + { + //TODO + + break; + } + } + } + pcmi_play_done(pcmi, nsamples); + + continue; + } + + // fill input buffers + pcmi_capt_init(pcmi, nsamples); + capt_num = 0; + for(const sp_app_system_source_t *source=sources; + source->type != SYSTEM_PORT_NONE; + source++) + { + switch(source->type) + { + case SYSTEM_PORT_NONE: + case SYSTEM_PORT_CONTROL: + case SYSTEM_PORT_CV: + case SYSTEM_PORT_OSC: + break; + + case SYSTEM_PORT_AUDIO: + { + chan_t *chan = source->sys_port; + + pcmi_capt_chan(pcmi, capt_num++, source->buf, nsamples); + + break; + } + + case SYSTEM_PORT_MIDI: + { + chan_t *chan = source->sys_port; + void *seq_in = source->buf; + + LV2_Atom_Forge *forge = &handle->forge; + LV2_Atom_Forge_Frame frame; + lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE); + lv2_atom_forge_sequence_head(forge, &frame, 0); + + uint8_t m [0x10]; + snd_seq_event_t *sev; + while(snd_seq_event_input_pending(handle->seq, 1) > 0) + { + snd_seq_event_input(handle->seq, &sev); //FIXME filter according to port + long len; + if((len = snd_midi_event_decode(chan->midi.trans, m, 0x10, sev)) > 0) + { + //add alsa midi event to in_buf + lv2_atom_forge_frame_time(forge, 0); //FIXME + lv2_atom_forge_atom(forge, len, handle->midi_MidiEvent); + lv2_atom_forge_raw(forge, m, len); + lv2_atom_forge_pad(forge, len); + } + else + fprintf(stderr, "event decode failed\n"); + + if(snd_seq_free_event(sev)) + fprintf(stderr, "event free failed\n"); + } + + lv2_atom_forge_pop(forge, &frame); + + break; + } + } + } + pcmi_capt_done(pcmi, nsamples); + + bin_process_pre(bin, nsamples, paused); + + // fill output buffers + pcmi_play_init(pcmi, nsamples); + play_num = 0; + for(const sp_app_system_sink_t *sink=sinks; + sink->type != SYSTEM_PORT_NONE; + sink++) + { + switch(sink->type) + { + case SYSTEM_PORT_NONE: + case SYSTEM_PORT_CONTROL: + case SYSTEM_PORT_CV: + case SYSTEM_PORT_OSC: + break; - pcmi_pcm_start(pcmi); + case SYSTEM_PORT_AUDIO: + { + chan_t *chan = sink->sys_port; - while(!prog->kill) + pcmi_play_chan(pcmi, play_num++, sink->buf, nsamples); + + break; + } + + case SYSTEM_PORT_MIDI: + { + chan_t *chan = sink->sys_port; + const LV2_Atom_Sequence *seq_out = sink->buf; + + LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev) + { + const LV2_Atom *atom = &ev->body; + + snd_seq_event_t sev; + snd_seq_ev_clear(&sev); + if(snd_midi_event_encode(chan->midi.trans, LV2_ATOM_BODY_CONST(atom), atom->size, &sev) != atom->size) + fprintf(stderr, "encode event failed\n"); + + // relative timestamp + struct snd_seq_real_time rtime = { + .tv_sec = 0, + //.tv_nsec = (float)time * 1e9 / module->host->srate + .tv_nsec = 0 + }; + + // schedule midi + snd_seq_ev_set_source(&sev, chan->midi.port); + snd_seq_ev_set_subs(&sev); // set broadcasting to subscribers + snd_seq_ev_schedule_real(&sev, handle->queue, 1, &rtime); // relative scheduling + snd_seq_event_output(handle->seq, &sev); + } + + break; + } + } + } + snd_seq_drain_output(handle->seq); + pcmi_play_done(pcmi, nsamples); + + bin_process_post(bin); + + na -= nsamples; + } + } + pcmi_pcm_stop(handle->pcmi); + + return NULL; +} + +static void * +_system_port_add(void *data, System_Port_Type type, const char *short_name, + const char *pretty_name, int input) +{ + bin_t *bin = data; + prog_t *handle = (void *)bin - offsetof(prog_t, bin); + + chan_t *chan = NULL; + + switch(type) { - int na = pcmi_pcm_wait(pcmi); + case SYSTEM_PORT_NONE: + { + // skip + break; + } - while(na >= prog->frsize) + case SYSTEM_PORT_CONTROL: { - if( ncapt) + // unsupported, skip + break; + } + + case SYSTEM_PORT_AUDIO: + { + chan = calloc(1, sizeof(chan_t)); + if(chan) { - pcmi_capt_init(pcmi, prog->frsize); - for(int i=0; i<ncapt; i++) - pcmi_capt_chan(pcmi, i, inp[i], prog->frsize); - pcmi_capt_done(pcmi, prog->frsize); + chan->type = CHAN_TYPE_PCMI; + //TODO } - if(nplay) + break; + } + case SYSTEM_PORT_CV: + { + // unsupported, skip + break; + } + + case SYSTEM_PORT_MIDI: + { + chan = calloc(1, sizeof(chan_t)); + if(chan) { - //memcpy(out[0], inp[0], prog->frsize * sizeof(float)); - //memcpy(out[1], inp[1], prog->frsize * sizeof(float)); + chan->type = CHAN_TYPE_MIDI; + + unsigned int caps = input + ? SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE + : SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ; - for(int i=0; i<nplay; i++) - for(int j=0; j<prog->frsize; j++) - out[i][j] = (float)rand() / RAND_MAX; + chan->midi.port = snd_seq_create_simple_port(handle->seq, short_name, + caps, SND_SEQ_PORT_TYPE_APPLICATION); + if(chan->midi.port < 0) + fprintf(stderr, "could not create port\n"); - pcmi_play_init(pcmi, prog->frsize); - for(int i=0; i<nplay; i++) - pcmi_play_chan(pcmi, i, out[i], prog->frsize); - pcmi_play_done(pcmi, prog->frsize); + if(snd_midi_event_new(0x10, &chan->midi.trans)) + fprintf(stderr, "could not create event\n"); + snd_midi_event_init(chan->midi.trans); + if(input) + snd_midi_event_reset_encode(chan->midi.trans); + else + snd_midi_event_reset_decode(chan->midi.trans); + snd_midi_event_no_status(chan->midi.trans, 1); } - na -= prog->frsize; + break; + } + case SYSTEM_PORT_OSC: + { + // unsupported, skip + break; } } - pcmi_pcm_stop(pcmi); + if(chan) + printf("channel add: %p %i %s\n", chan, chan->type, short_name); - return NULL; + return chan; } + +static void +_system_port_del(void *data, void *sys_port) +{ + bin_t *bin = data; + prog_t *handle = (void *)bin - offsetof(prog_t, bin); + + chan_t *chan = sys_port; + + if(!chan || !handle->seq) + return; + + printf("channel_del: %p %i\n", chan, chan->type); + + switch(chan->type) + { + case CHAN_TYPE_PCMI: + { + //TODO + + break; + } + case CHAN_TYPE_MIDI: + { + snd_midi_event_free(chan->midi.trans); + snd_seq_delete_simple_port(handle->seq, chan->midi.port); + + break; + } + } + + free(chan); +} + +#if defined(BUILD_UI) +static void +_ui_saved(void *data, int status) +{ + bin_t *bin = data; + prog_t *handle = (void *)bin - offsetof(prog_t, bin); + + //printf("_ui_saved: %i\n", status); + if(handle->save_state == SAVE_STATE_NSM) + { + synthpod_nsm_saved(bin->nsm, status); + } + handle->save_state = SAVE_STATE_INTERNAL; + + if(handle->kill) + { + elm_exit(); + } +} +#endif // BUILD_UI + +static int +_alsa_init(prog_t *handle) +{ + // init alsa sequencer + if(snd_seq_open(&handle->seq, "hw", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK)) + fprintf(stderr, "could not open sequencer\n"); + if(snd_seq_set_client_name(handle->seq, "Synthpod")) + fprintf(stderr, "could not set name\n"); + handle->queue = snd_seq_alloc_queue(handle->seq); + if(handle->queue < 0) + fprintf(stderr, "could not allocate queue\n"); + snd_seq_start_queue(handle->seq, handle->queue, NULL); + + // init alsa pcm + handle->pcmi = pcmi_new(handle->play_name, handle->capt_name, handle->srate, handle->frsize, handle->nfrags, handle->twochan); + pcmi_printinfo(handle->pcmi); + + return 0; +} + +static void +_alsa_deinit(prog_t *handle) +{ + handle->kill = 1; + eina_thread_join(handle->thread); + + pcmi_free(handle->pcmi); + handle->pcmi = NULL; + + if(snd_seq_drain_output(handle->seq)) + fprintf(stderr, "draining output failed\n"); + snd_seq_stop_queue(handle->seq, handle->queue, NULL); + if(snd_seq_free_queue(handle->seq, handle->queue)) + fprintf(stderr, "freeing queue failed\n"); + if(snd_seq_close(handle->seq)) + fprintf(stderr, "close sequencer failed\n"); + handle->seq = NULL; + handle->queue = 0; +} + +static int +_open(const char *path, const char *name, const char *id, void *data) +{ + bin_t *bin = data; + prog_t *handle = (void *)bin - offsetof(prog_t, bin); + (void)name; + + if(bin->path) + free(bin->path); + bin->path = strdup(path); + + // alsa init + if(_alsa_init(handle)) + return -1; + + // synthpod init + bin->app_driver.sample_rate = handle->srate; + bin->app_driver.max_block_size = handle->frsize; + bin->app_driver.min_block_size = 1; + bin->app_driver.seq_size = SEQ_SIZE; + + // app init + bin->app = sp_app_new(NULL, &bin->app_driver, bin); + + // alsa activate + Eina_Bool status = eina_thread_create(&handle->thread, + EINA_THREAD_URGENT, -1, _rt_thread, handle); //TODO + + sleep(1); + +#if defined(BUILD_UI) //FIXME + sp_ui_bundle_load(bin->ui, bin->path, 1); +#endif + + return 0; // success +} + +static int +_save(void *data) +{ + bin_t *bin = data; + prog_t *handle = (void *)bin - offsetof(prog_t, bin); + + handle->save_state = SAVE_STATE_NSM; +#if defined(BUILD_UI) //FIXME + sp_ui_bundle_save(bin->ui, bin->path, 1); +#endif + + return 0; // success +} + +static const synthpod_nsm_driver_t nsm_driver = { + .open = _open, + .save = _save, +#if defined(BUILD_UI) + .show = _show, + .hide = _hide +#else + .show = NULL, + .hide = NULL +#endif // BUILD_UI +}; #if defined(BUILD_UI) EAPI_MAIN int @@ -109,15 +527,17 @@ int main(int argc, char **argv) #endif { - static prog_t prog; - prog.srate = 48000; - prog.frsize = 1024; - prog.nfrags = 3; - int twochan = 0; + static prog_t handle; + bin_t *bin = &handle.bin; + + handle.srate = 48000; + handle.frsize = 1024; + handle.nfrags = 3; + handle.twochan = 0; const char *def = "default"; - const char *play_name = def; - const char *capt_name = def; + handle.play_name = def; + handle.capt_name = def; int c; while((c = getopt(argc, argv, "vh2i:o:r:p:n:s:")) != -1) @@ -160,22 +580,22 @@ main(int argc, char **argv) , argv[0]); return 0; case '2': - twochan = 1; + handle.twochan = 1; break; case 'i': - capt_name = optarg; + handle.capt_name = optarg; break; case 'o': - play_name = optarg; + handle.play_name = optarg; break; case 'r': - prog.srate = atoi(optarg); + handle.srate = atoi(optarg); break; case 'p': - prog.frsize = atoi(optarg); + handle.frsize = atoi(optarg); break; case 'n': - prog.nfrags = atoi(optarg); + handle.nfrags = atoi(optarg); break; case 's': //TODO @@ -193,32 +613,42 @@ main(int argc, char **argv) return -1; } } - - prog.pcmi = pcmi_new(play_name, capt_name, prog.srate, prog.frsize, prog.nfrags, twochan); - pcmi_printinfo(prog.pcmi); - Eina_Bool status = eina_thread_create(&prog.thread, - EINA_THREAD_URGENT, -1, _rt_thread, &prog); //TODO - - // create main window - //ui_anim = ecore_animator_add(_ui_animator, &handle); - Evas_Object *win = elm_win_util_standard_add("synthpod", "Synthpod"); - //evas_object_smart_callback_add(win, "delete,request", _ui_delete_request, &handle); - evas_object_resize(win, 1280, 720); - evas_object_show(win); + bin_init(bin); + + LV2_URID_Map *map = ext_urid_map_get(bin->ext_urid); + LV2_URID_Unmap *unmap = ext_urid_unmap_get(bin->ext_urid); + + lv2_atom_forge_init(&handle.forge, map); + + handle.midi_MidiEvent = map->map(map->handle, LV2_MIDI__MidiEvent); + + bin->app_driver.system_port_add = _system_port_add; + bin->app_driver.system_port_del = _system_port_del; + + bin->app_driver.osc_sched = NULL; #if defined(BUILD_UI) - elm_run(); -#else - ecore_main_loop_begin(); + bin->ui_driver.saved = _ui_saved; + + bin->ui_driver.features = SP_UI_FEATURE_NEW | SP_UI_FEATURE_SAVE | SP_UI_FEATURE_CLOSE; + if(synthpod_nsm_managed()) + bin->ui_driver.features |= SP_UI_FEATURE_IMPORT_FROM | SP_UI_FEATURE_EXPORT_TO; + else + bin->ui_driver.features |= SP_UI_FEATURE_OPEN | SP_UI_FEATURE_SAVE_AS; #endif - evas_object_del(win); + // run + bin_run(bin, argv, &nsm_driver); + + // stop + bin_stop(bin); - prog.kill = 1; - eina_thread_join(prog.thread); + // deinit alsa + _alsa_deinit(&handle); - pcmi_free(prog.pcmi); + // deinit + bin_deinit(bin); return 0; } diff --git a/bin/synthpod_bin.h b/bin/synthpod_bin.h new file mode 100644 index 00000000..64380dc3 --- /dev/null +++ b/bin/synthpod_bin.h @@ -0,0 +1,532 @@ +/* + * Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef SYNTHPOD_COMMON_H +#define SYNTHPOD_COMMON_H + +#include <synthpod_app.h> + +#if defined(BUILD_UI) +# include <synthpod_ui.h> +#else +# include <Ecore.h> +# include <Ecore_File.h> +#endif + +#include <Eina.h> + +#include <ext_urid.h> +#include <varchunk.h> +#include <lv2_osc.h> +#include <osc.h> + +#include <synthpod_nsm.h> + +#include <lv2/lv2plug.in/ns/ext/atom/atom.h> +#include <lv2/lv2plug.in/ns/ext/atom/forge.h> +#include <lv2/lv2plug.in/ns/ext/midi/midi.h> +#include <lv2/lv2plug.in/ns/ext/urid/urid.h> +#include <lv2/lv2plug.in/ns/ext/worker/worker.h> +#include <lv2/lv2plug.in/ns/ext/state/state.h> +#include <lv2/lv2plug.in/ns/ext/log/log.h> +#include <lv2/lv2plug.in/ns/ext/time/time.h> + +#define SEQ_SIZE 0x2000 +#define CHUNK_SIZE 0x10000 + +typedef enum _save_state_t save_state_t; + +enum _save_state_t { + SAVE_STATE_INTERNAL = 0, + SAVE_STATE_NSM, + SAVE_STATE_JACK +}; + +typedef struct _bin_t bin_t; + +struct _bin_t { + ext_urid_t *ext_urid; + + sp_app_t *app; + sp_app_driver_t app_driver; + + varchunk_t *app_to_worker; + varchunk_t *app_from_worker; + varchunk_t *app_to_log; + + char *path; + synthpod_nsm_t *nsm; + +#if defined(BUILD_UI) + sp_ui_t *ui; + sp_ui_driver_t ui_driver; + + varchunk_t *app_to_ui; + varchunk_t *app_from_ui; + + Ecore_Animator *ui_anim; + Evas_Object *win; +#else + Ecore_Event_Handler *sig; +#endif + + volatile int worker_dead; + Eina_Thread worker_thread; + Eina_Semaphore worker_sem; + bool worker_sem_needs_release; + + LV2_URID log_entry; + LV2_URID log_error; + LV2_URID log_note; + LV2_URID log_trace; + LV2_URID log_warning; +}; + +#if defined(BUILD_UI) +// non-rt ui-thread +static void +_ui_delete_request(void *data, Evas_Object *obj, void *event) +{ + elm_exit(); +} + +static void +_ui_close(void *data) +{ + //printf("_ui_close\n"); + elm_exit(); +} + + static void +_ui_opened(void *data, int status) +{ + bin_t *bin = data; + + //printf("_ui_opened: %i\n", status); + synthpod_nsm_opened(bin->nsm, status); +} + +// non-rt ui-thread +static Eina_Bool +_ui_animator(void *data) +{ + bin_t *bin = data; + + size_t size; + const LV2_Atom *atom; + while((atom = varchunk_read_request(bin->app_to_ui, &size))) + { + sp_ui_from_app(bin->ui, atom); + varchunk_read_advance(bin->app_to_ui); + } + + return EINA_TRUE; // continue animator +} +#else +static Eina_Bool +_quit(void *data, int type, void *info) +{ + ecore_main_loop_quit(); + + return EINA_TRUE; +} +#endif // BUILD_UI + +// non-rt worker-thread +static void * +_worker_thread(void *data, Eina_Thread thread) +{ + bin_t *bin = data; + + pthread_t self = pthread_self(); + + struct sched_param schedp; + memset(&schedp, 0, sizeof(struct sched_param)); + schedp.sched_priority = 60; //TODO make configurable + + if(schedp.sched_priority) + { + if(pthread_setschedparam(self, SCHED_RR, &schedp)) + fprintf(stderr, "pthread_setschedparam error\n"); + } + + while(!bin->worker_dead) + { + eina_semaphore_lock(&bin->worker_sem); + + size_t size; + const void *body; + while((body = varchunk_read_request(bin->app_to_worker, &size))) + { + sp_worker_from_app(bin->app, size, body); + varchunk_read_advance(bin->app_to_worker); + } + + const char *trace; + while((trace = varchunk_read_request(bin->app_to_log, &size))) + { + fprintf(stderr, "[Trace] %s\n", trace); + + varchunk_read_advance(bin->app_to_log); + } + } + + return NULL; +} + +#if defined(BUILD_UI) +// rt +static void * +_app_to_ui_request(size_t size, void *data) +{ + bin_t *bin = data; + + return varchunk_write_request(bin->app_to_ui, size); +} +static void +_app_to_ui_advance(size_t size, void *data) +{ + bin_t *bin = data; + + varchunk_write_advance(bin->app_to_ui, size); +} + +// non-rt ui-thread +static void * +_ui_to_app_request(size_t size, void *data) +{ + bin_t *bin = data; + + void *ptr; + do + { + ptr = varchunk_write_request(bin->app_from_ui, size); + } + while(!ptr); // wait until there is enough space + + return ptr; +} +static void +_ui_to_app_advance(size_t size, void *data) +{ + bin_t *bin = data; + + varchunk_write_advance(bin->app_from_ui, size); +} +#endif + +// rt +static void * +_app_to_worker_request(size_t size, void *data) +{ + bin_t *bin = data; + + return varchunk_write_request(bin->app_to_worker, size); +} +static void +_app_to_worker_advance(size_t size, void *data) +{ + bin_t *bin = data; + + varchunk_write_advance(bin->app_to_worker, size); + bin->worker_sem_needs_release = true; +} + +// non-rt worker-thread +static void * +_worker_to_app_request(size_t size, void *data) +{ + bin_t *bin = data; + + void *ptr; + do + { + ptr = varchunk_write_request(bin->app_from_worker, size); + } + while(!ptr); // wait until there is enough space + + return ptr; +} +static void +_worker_to_app_advance(size_t size, void *data) +{ + bin_t *bin = data; + + varchunk_write_advance(bin->app_from_worker, size); +} + +// non-rt || rt with LV2_LOG__Trace +static int +_log_vprintf(void *data, LV2_URID type, const char *fmt, va_list args) +{ + bin_t *bin = data; + + if(type == bin->log_trace) + { + char *trace; + if((trace = varchunk_write_request(bin->app_to_log, 1024))) + { + vsprintf(trace, fmt, args); + + size_t written = strlen(trace) + 1; + varchunk_write_advance(bin->app_to_log, written); + bin->worker_sem_needs_release = true; + } + } + else // !log_trace + { + const char *type_str = NULL; + if(type == bin->log_entry) + type_str = "Entry"; + else if(type == bin->log_error) + type_str = "Error"; + else if(type == bin->log_note) + type_str = "Note"; + else if(type == bin->log_warning) + type_str = "Warning"; + + //TODO send to UI? + + fprintf(stderr, "[%s] ", type_str); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + + return 0; + } + + return -1; +} + +// non-rt || rt with LV2_LOG__Trace +static int +_log_printf(void *data, LV2_URID type, const char *fmt, ...) +{ + va_list args; + int ret; + + va_start (args, fmt); + ret = _log_vprintf(data, type, fmt, args); + va_end(args); + + return ret; +} + +#if defined(BUILD_UI) +static int +_show(void *data) +{ + bin_t *bin = data; + + evas_object_show(bin->win); + + return 0; +} + +static int +_hide(void *data) +{ + bin_t *bin = data; + + evas_object_hide(bin->win); + + return 0; +} +#endif // BUILD_UI + +static void +bin_init(bin_t *bin) +{ + // varchunk init +#if defined(BUILD_UI) + bin->app_to_ui = varchunk_new(CHUNK_SIZE); + bin->app_from_ui = varchunk_new(CHUNK_SIZE); +#endif + bin->app_to_worker = varchunk_new(CHUNK_SIZE); + bin->app_from_worker = varchunk_new(CHUNK_SIZE); + bin->app_to_log = varchunk_new(CHUNK_SIZE); + + bin->ext_urid = ext_urid_new(); + LV2_URID_Map *map = ext_urid_map_get(bin->ext_urid); + LV2_URID_Unmap *unmap = ext_urid_unmap_get(bin->ext_urid); + + bin->log_entry = map->map(map->handle, LV2_LOG__Entry); + bin->log_error = map->map(map->handle, LV2_LOG__Error); + bin->log_note = map->map(map->handle, LV2_LOG__Note); + bin->log_trace = map->map(map->handle, LV2_LOG__Trace); + bin->log_warning = map->map(map->handle, LV2_LOG__Warning); + + bin->app_driver.map = map; + bin->app_driver.unmap = unmap; + bin->app_driver.log_printf = _log_printf; + bin->app_driver.log_vprintf = _log_vprintf; +#if defined(BUILD_UI) + bin->app_driver.to_ui_request = _app_to_ui_request; + bin->app_driver.to_ui_advance = _app_to_ui_advance; +#else + bin->app_driver.to_ui_request = NULL; + bin->app_driver.to_ui_advance = NULL; +#endif + bin->app_driver.to_worker_request = _app_to_worker_request; + bin->app_driver.to_worker_advance = _app_to_worker_advance; + bin->app_driver.to_app_request = _worker_to_app_request; + bin->app_driver.to_app_advance = _worker_to_app_advance; + +#if defined(BUILD_UI) + bin->ui_driver.map = map; + bin->ui_driver.unmap = unmap; + bin->ui_driver.to_app_request = _ui_to_app_request; + bin->ui_driver.to_app_advance = _ui_to_app_advance; + bin->ui_driver.instance_access = 1; // enabled + + bin->ui_driver.opened = _ui_opened; + bin->ui_driver.close = _ui_close; +#endif +} + +static void +bin_run(bin_t *bin, char **argv, const synthpod_nsm_driver_t *nsm_driver) +{ +#if defined(BUILD_UI) + // create main window + bin->ui_anim = ecore_animator_add(_ui_animator, bin); + bin->win = elm_win_util_standard_add("synthpod", "Synthpod"); + evas_object_smart_callback_add(bin->win, "delete,request", _ui_delete_request, NULL); + evas_object_resize(bin->win, 1280, 720); + evas_object_show(bin->win); + + // ui init + bin->ui = sp_ui_new(bin->win, NULL, &bin->ui_driver, bin, 1); +#endif + + // NSM init + const char *exe = strrchr(argv[0], '/'); + exe = exe ? exe + 1 : argv[0]; // we only want the program name without path + bin->nsm = synthpod_nsm_new(exe, argv[optind], nsm_driver, bin); //TODO check + + // init semaphores + eina_semaphore_new(&bin->worker_sem, 0); + + // threads init + Eina_Bool status = eina_thread_create(&bin->worker_thread, + EINA_THREAD_URGENT, -1, _worker_thread, bin); //TODO + +#if defined(BUILD_UI) + // main loop + elm_run(); + + // ui deinit + sp_ui_free(bin->ui); + + evas_object_del(bin->win); + ecore_animator_del(bin->ui_anim); +#else + bin->sig = ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, _quit, NULL); + + ecore_main_loop_begin(); + + ecore_event_handler_del(bin->sig); +#endif // BUILD_UI +} + +static void +bin_stop(bin_t *bin) +{ + // threads deinit + bin->worker_dead = 1; // atomic operation + eina_semaphore_release(&bin->worker_sem, 1); + eina_thread_join(bin->worker_thread); + + // NSM deinit + synthpod_nsm_free(bin->nsm); + + // deinit semaphores + eina_semaphore_free(&bin->worker_sem); + + if(bin->path) + free(bin->path); +} + +static void +bin_deinit(bin_t *bin) +{ + // synthpod deinit + sp_app_free(bin->app); + + // ext_urid deinit + ext_urid_free(bin->ext_urid); + + // varchunk deinit +#if defined(BUILD_UI) + varchunk_free(bin->app_to_ui); + varchunk_free(bin->app_from_ui); +#endif + varchunk_free(bin->app_to_log); + varchunk_free(bin->app_to_worker); + varchunk_free(bin->app_from_worker); +} + +static inline void +bin_process_pre(bin_t *bin, uint32_t nsamples, int paused) +{ + // read events from worker + if(!paused) // aka not saving state + { + size_t size; + const void *body; + int n = 0; + while((body = varchunk_read_request(bin->app_from_worker, &size)) + && (n++ < 10) ) //FIXME limit to how many events? + { + sp_app_from_worker(bin->app, size, body); + varchunk_read_advance(bin->app_from_worker); + } + } + + // run synthpod app pre + sp_app_run_pre(bin->app, nsamples); + +#if defined(BUILD_UI) + // read events from UI + if(!paused) // aka not saving state + { + size_t size; + const LV2_Atom *atom; + int n = 0; + while((atom = varchunk_read_request(bin->app_from_ui, &size)) + && (n++ < 10) ) //FIXME limit to how many events? + { + sp_app_from_ui(bin->app, atom); + varchunk_read_advance(bin->app_from_ui); + } + } +#endif // BUILD_UI + + // run synthpod app post + sp_app_run_post(bin->app, nsamples); +} + +static inline void +bin_process_post(bin_t *bin) +{ + if(bin->worker_sem_needs_release) + { + eina_semaphore_release(&bin->worker_sem, 1); + bin->worker_sem_needs_release = false; + } +} + +#endif diff --git a/bin/synthpod_jack.c b/bin/synthpod_jack.c index 9489f5da..e324243c 100644 --- a/bin/synthpod_jack.c +++ b/bin/synthpod_jack.c @@ -20,28 +20,7 @@ #include <unistd.h> #include <assert.h> -#include <synthpod_app.h> -#if defined(BUILD_UI) -# include <synthpod_ui.h> -#else -# include <Ecore.h> -# include <Ecore_File.h> -#endif -#include <ext_urid.h> -#include <varchunk.h> -#include <lv2_osc.h> -#include <osc.h> - -#include <synthpod_nsm.h> - -#include <lv2/lv2plug.in/ns/ext/atom/atom.h> -#include <lv2/lv2plug.in/ns/ext/atom/forge.h> -#include <lv2/lv2plug.in/ns/ext/midi/midi.h> -#include <lv2/lv2plug.in/ns/ext/urid/urid.h> -#include <lv2/lv2plug.in/ns/ext/worker/worker.h> -#include <lv2/lv2plug.in/ns/ext/state/state.h> -#include <lv2/lv2plug.in/ns/ext/log/log.h> -#include <lv2/lv2plug.in/ns/ext/time/time.h> +#include <synthpod_bin.h> #include <jack/jack.h> #include <jack/midiport.h> @@ -52,56 +31,17 @@ # include <jack/uuid.h> #endif -#include <Eina.h> - #ifndef MAX # define MAX(A, B) ((A) > (B) ? (A) : (B)) #endif -#define CHUNK_SIZE 0x10000 -#define SEQ_SIZE 0x2000 #define OSC_SIZE 0x800 +#define JAN_1970 (uint64_t)0x83aa7e80 -# define JAN_1970 (uint64_t)0x83aa7e80 - -typedef enum _save_state_t save_state_t; typedef struct _prog_t prog_t; -enum _save_state_t { - SAVE_STATE_INTERNAL = 0, - SAVE_STATE_NSM, - SAVE_STATE_JACK -}; - struct _prog_t { - ext_urid_t *ext_urid; - - sp_app_t *app; - sp_app_driver_t app_driver; - - varchunk_t *app_to_worker; - varchunk_t *app_from_worker; - - varchunk_t *app_to_log; - - char *path; - synthpod_nsm_t *nsm; - -#if defined(BUILD_UI) - sp_ui_t *ui; - sp_ui_driver_t ui_driver; - - varchunk_t *app_to_ui; - varchunk_t *app_from_ui; - - varchunk_t *ui_to_app; - varchunk_t *ui_from_app; - - Ecore_Animator *ui_anim; - Evas_Object *win; -#else - Ecore_Event_Handler *sig; -#endif + bin_t bin; LV2_Atom_Forge forge; @@ -117,12 +57,6 @@ struct _prog_t { LV2_URID midi_MidiEvent; - LV2_URID log_entry; - LV2_URID log_error; - LV2_URID log_note; - LV2_URID log_trace; - LV2_URID log_warning; - LV2_URID time_position; LV2_URID time_barBeat; LV2_URID time_bar; @@ -141,11 +75,6 @@ struct _prog_t { jack_client_t *client; jack_session_event_t *session_event; uint32_t seq_size; - - volatile int worker_dead; - Eina_Thread worker_thread; - Eina_Semaphore worker_sem; - bool worker_sem_needs_release; struct { jack_transport_state_t rolling; @@ -171,76 +100,6 @@ struct _prog_t { #endif }; -static const synthpod_nsm_driver_t nsm_driver; // forwared-declaration - -// non-rt worker-thread -static void * -_worker_thread(void *data, Eina_Thread thread) -{ - prog_t *handle = data; - - while(!handle->worker_dead) - { - eina_semaphore_lock(&handle->worker_sem); - - size_t size; - const void *body; - while((body = varchunk_read_request(handle->app_to_worker, &size))) - { - sp_worker_from_app(handle->app, size, body); - varchunk_read_advance(handle->app_to_worker); - } - - const char *trace; - while((trace = varchunk_read_request(handle->app_to_log, &size))) - { - fprintf(stderr, "[Trace] %s\n", trace); - - varchunk_read_advance(handle->app_to_log); - } - } - - return NULL; -} - -#if defined(BUILD_UI) -// non-rt ui-thread -static void -_ui_delete_request(void *data, Evas_Object *obj, void *event) -{ - prog_t *handle = data; - - elm_exit(); -} - -// non-rt ui-thread -static Eina_Bool -_ui_animator(void *data) -{ - prog_t *handle = data; - - size_t size; - const LV2_Atom *atom; - while((atom = varchunk_read_request(handle->app_to_ui, &size))) - { - sp_ui_from_app(handle->ui, atom); - varchunk_read_advance(handle->app_to_ui); - } - - return EINA_TRUE; // continue animator -} -#else -static Eina_Bool -_quit(void *data, int type, void *info) -{ - prog_t *handle = data; - - ecore_main_loop_quit(); - - return EINA_TRUE; -} -#endif // BUILD_UI - static void _trans_event(prog_t *prog, LV2_Atom_Forge *forge, int rolling, jack_position_t *pos) { @@ -532,7 +391,8 @@ static int _process(jack_nframes_t nsamples, void *data) { prog_t *handle = data; - sp_app_t *app = handle->app; + bin_t *bin = &handle->bin; + sp_app_t *app = bin->app; #if defined(JACK_HAS_CYCLE_TIMES) clock_gettime(CLOCK_REALTIME, &handle->ntp); @@ -703,41 +563,7 @@ _process(jack_nframes_t nsamples, void *data) handle->trans.ticks_per_beat = pos.ticks_per_beat; handle->trans.beats_per_minute = pos.beats_per_minute; - // read events from worker - if(!paused) // aka not saving state - { - size_t size; - const void *body; - int n = 0; - while((body = varchunk_read_request(handle->app_from_worker, &size)) - && (n++ < 10) ) //FIXME limit to how many events? - { - sp_app_from_worker(handle->app, size, body); - varchunk_read_advance(handle->app_from_worker); - } - } - - // run synthpod app pre - sp_app_run_pre(handle->app, nsamples); - -#if defined(BUILD_UI) - // read events from UI - if(!paused) // aka not saving state - { - size_t size; - const LV2_Atom *atom; - int n = 0; - while((atom = varchunk_read_request(handle->app_from_ui, &size)) - && (n++ < 10) ) //FIXME limit to how many events? - { - sp_app_from_ui(handle->app, atom); - varchunk_read_advance(handle->app_from_ui); - } - } -#endif // BUILD_UI - - // run synthpod app post - sp_app_run_post(handle->app, nsamples); + bin_process_pre(bin, nsamples, paused); // fill output buffers for(const sp_app_system_sink_t *sink=sinks; @@ -814,11 +640,7 @@ _process(jack_nframes_t nsamples, void *data) } } - if(handle->worker_sem_needs_release) - { - eina_semaphore_release(&handle->worker_sem, 1); - handle->worker_sem_needs_release = false; - } + bin_process_post(bin); return 0; } @@ -828,6 +650,7 @@ static void _session_async(void *data) { prog_t *handle = data; + bin_t *bin = &handle->bin; jack_session_event_t *ev = handle->session_event; @@ -847,14 +670,14 @@ _session_async(void *data) case JackSessionSave: handle->save_state = SAVE_STATE_JACK; #if defined(BUILD_UI) //FIXME - sp_ui_bundle_save(handle->ui, ev->session_dir, 1); + sp_ui_bundle_save(bin->ui, ev->session_dir, 1); #endif break; case JackSessionSaveTemplate: handle->save_state = SAVE_STATE_JACK; #if defined(BUILD_UI) //FIXME - sp_ui_bundle_new(handle->ui); - sp_ui_bundle_save(handle->ui, ev->session_dir, 1); + sp_ui_bundle_new(bin->ui); + sp_ui_bundle_save(bin->ui, ev->session_dir, 1); #endif break; } @@ -875,12 +698,13 @@ static int _buffer_size(jack_nframes_t block_size, void *data) { prog_t *handle = data; + bin_t *bin = &handle->bin; //printf("JACK: new buffer size: %p %u %u\n", // handle->app, handle->app_driver.max_block_size, block_size); - if(handle->app) - return sp_app_nominal_block_length(handle->app, block_size); + if(bin->app) + return sp_app_nominal_block_length(bin->app, block_size); return 0; } @@ -890,68 +714,25 @@ static int _sample_rate(jack_nframes_t sample_rate, void *data) { prog_t *handle = data; + bin_t *bin = &handle->bin; - if(handle->app && (sample_rate != handle->app_driver.sample_rate) ) + if(bin->app && (sample_rate != bin->app_driver.sample_rate) ) fprintf(stderr, "synthpod does not support dynamic sample rate changes\n"); return 0; } #if defined(BUILD_UI) -// rt -static void * -_app_to_ui_request(size_t size, void *data) -{ - prog_t *handle = data; - - return varchunk_write_request(handle->app_to_ui, size); -} -static void -_app_to_ui_advance(size_t size, void *data) -{ - prog_t *handle = data; - - varchunk_write_advance(handle->app_to_ui, size); -} - -// non-rt ui-thread -static void * -_ui_to_app_request(size_t size, void *data) -{ - prog_t *handle = data; - - void *ptr; - do - ptr = varchunk_write_request(handle->app_from_ui, size); - while(!ptr); // wait until there is enough space - - return ptr; -} -static void -_ui_to_app_advance(size_t size, void *data) -{ - prog_t *handle = data; - - varchunk_write_advance(handle->app_from_ui, size); -} - -static void -_ui_opened(void *data, int status) -{ - prog_t *handle = data; - - //printf("_ui_opened: %i\n", status); - synthpod_nsm_opened(handle->nsm, status); -} static void _ui_saved(void *data, int status) { - prog_t *handle = data; + bin_t *bin = data; + prog_t *handle = (void *)bin - offsetof(prog_t, bin); //printf("_ui_saved: %i\n", status); if(handle->save_state == SAVE_STATE_NSM) { - synthpod_nsm_saved(handle->nsm, status); + synthpod_nsm_saved(bin->nsm, status); } else if(handle->save_state == SAVE_STATE_JACK) { @@ -969,122 +750,17 @@ _ui_saved(void *data, int status) if(handle->kill) { -#if defined(BUILD_UI) elm_exit(); -#else - ecore_main_loop_quit(); -#endif } } -static void -_ui_close(void *data) -{ - prog_t *handle = data; - - //printf("_ui_close\n"); - elm_exit(); -} #endif // BUILD_UI -// rt -static void * -_app_to_worker_request(size_t size, void *data) -{ - prog_t *handle = data; - - return varchunk_write_request(handle->app_to_worker, size); -} -static void -_app_to_worker_advance(size_t size, void *data) -{ - prog_t *handle = data; - - varchunk_write_advance(handle->app_to_worker, size); - handle->worker_sem_needs_release = true; -} - -// non-rt worker-thread -static void * -_worker_to_app_request(size_t size, void *data) -{ - prog_t *handle = data; - - void *ptr; - do - ptr = varchunk_write_request(handle->app_from_worker, size); - while(!ptr); // wait until there is enough space - - return ptr; -} -static void -_worker_to_app_advance(size_t size, void *data) -{ - prog_t *handle = data; - - varchunk_write_advance(handle->app_from_worker, size); -} - -// non-rt || rt with LV2_LOG__Trace -static int -_log_vprintf(void *data, LV2_URID type, const char *fmt, va_list args) -{ - prog_t *handle = data; - - if(type == handle->log_trace) - { - char *trace; - if((trace = varchunk_write_request(handle->app_to_log, 1024))) - { - vsprintf(trace, fmt, args); - - size_t written = strlen(trace) + 1; - varchunk_write_advance(handle->app_to_log, written); - handle->worker_sem_needs_release = true; - } - } - else // !log_trace - { - const char *type_str = NULL; - if(type == handle->log_entry) - type_str = "Entry"; - else if(type == handle->log_error) - type_str = "Error"; - else if(type == handle->log_note) - type_str = "Note"; - else if(type == handle->log_warning) - type_str = "Warning"; - - //TODO send to UI? - - fprintf(stderr, "[%s] ", type_str); - vfprintf(stderr, fmt, args); - fputc('\n', stderr); - - return 0; - } - - return -1; -} - -// non-rt || rt with LV2_LOG__Trace -static int -_log_printf(void *data, LV2_URID type, const char *fmt, ...) -{ - va_list args; - int ret; - - va_start (args, fmt); - ret = _log_vprintf(data, type, fmt, args); - va_end(args); - - return ret; -} - static void * _system_port_add(void *data, System_Port_Type type, const char *short_name, const char *pretty_name, int input) { - prog_t *handle = data; + bin_t *bin = data; + prog_t *handle = (void *)bin - offsetof(prog_t, bin); //printf("_system_port_add: %s\n", short_name); @@ -1166,9 +842,9 @@ _system_port_add(void *data, System_Port_Type type, const char *short_name, static void _system_port_del(void *data, void *sys_port) { - //printf("_system_port_del\n"); + bin_t *bin = data; + prog_t *handle = (void *)bin - offsetof(prog_t, bin); - prog_t *handle = data; jack_port_t *jack_port = sys_port; if(!jack_port || !handle->client) @@ -1288,32 +964,33 @@ _jack_deinit(prog_t *handle) static int _open(const char *path, const char *name, const char *id, void *data) { + bin_t *bin = data; + prog_t *handle = (void *)bin - offsetof(prog_t, bin); (void)name; - prog_t *handle = data; - if(handle->path) - free(handle->path); - handle->path = strdup(path); + if(bin->path) + free(bin->path); + bin->path = strdup(path); // jack init if(_jack_init(handle, id)) return -1; // synthpod init - handle->app_driver.sample_rate = jack_get_sample_rate(handle->client); - handle->app_driver.max_block_size = jack_get_buffer_size(handle->client); - handle->app_driver.min_block_size = 1; - handle->app_driver.seq_size = MAX(handle->seq_size, + bin->app_driver.sample_rate = jack_get_sample_rate(handle->client); + bin->app_driver.max_block_size = jack_get_buffer_size(handle->client); + bin->app_driver.min_block_size = 1; + bin->app_driver.seq_size = MAX(handle->seq_size, jack_port_type_get_buffer_size(handle->client, JACK_DEFAULT_MIDI_TYPE)); // app init - handle->app = sp_app_new(NULL, &handle->app_driver, handle); + bin->app = sp_app_new(NULL, &bin->app_driver, bin); // jack activate jack_activate(handle->client); //TODO check #if defined(BUILD_UI) //FIXME - sp_ui_bundle_load(handle->ui, handle->path, 1); + sp_ui_bundle_load(bin->ui, bin->path, 1); #endif return 0; // success @@ -1322,38 +999,17 @@ _open(const char *path, const char *name, const char *id, void *data) static int _save(void *data) { - prog_t *handle = data; + bin_t *bin = data; + prog_t *handle = (void *)bin - offsetof(prog_t, bin); handle->save_state = SAVE_STATE_NSM; #if defined(BUILD_UI) //FIXME - sp_ui_bundle_save(handle->ui, handle->path, 1); + sp_ui_bundle_save(bin->ui, bin->path, 1); #endif return 0; // success } -#if defined(BUILD_UI) -static int -_show(void *data) -{ - prog_t *handle = data; - - evas_object_show(handle->win); - - return 0; -} - -static int -_hide(void *data) -{ - prog_t *handle = data; - - evas_object_hide(handle->win); - - return 0; -} -#endif // BUILD_UI - static const synthpod_nsm_driver_t nsm_driver = { .open = _open, .save = _save, @@ -1427,6 +1083,7 @@ main(int argc, char **argv) #endif { static prog_t handle; + bin_t *bin = &handle.bin; handle.server_name = NULL; handle.session_id = NULL; @@ -1490,32 +1147,16 @@ main(int argc, char **argv) } } - // varchunk init -#if defined(BUILD_UI) - handle.app_to_ui = varchunk_new(CHUNK_SIZE); - handle.app_from_ui = varchunk_new(CHUNK_SIZE); -#endif - handle.app_to_worker = varchunk_new(CHUNK_SIZE); - handle.app_from_worker = varchunk_new(CHUNK_SIZE); - - handle.app_to_log = varchunk_new(CHUNK_SIZE); + bin_init(bin); - // ext_urid init - handle.ext_urid = ext_urid_new(); - LV2_URID_Map *map = ext_urid_map_get(handle.ext_urid); - LV2_URID_Unmap *unmap = ext_urid_unmap_get(handle.ext_urid); + LV2_URID_Map *map = ext_urid_map_get(bin->ext_urid); + LV2_URID_Unmap *unmap = ext_urid_unmap_get(bin->ext_urid); lv2_atom_forge_init(&handle.forge, map); osc_forge_init(&handle.oforge, map); handle.midi_MidiEvent = map->map(map->handle, LV2_MIDI__MidiEvent); - handle.log_entry = map->map(map->handle, LV2_LOG__Entry); - handle.log_error = map->map(map->handle, LV2_LOG__Error); - handle.log_note = map->map(map->handle, LV2_LOG__Note); - handle.log_trace = map->map(map->handle, LV2_LOG__Trace); - handle.log_warning = map->map(map->handle, LV2_LOG__Warning); - handle.time_position = map->map(map->handle, LV2_TIME__Position); handle.time_barBeat = map->map(map->handle, LV2_TIME__barBeat); handle.time_bar = map->map(map->handle, LV2_TIME__bar); @@ -1526,119 +1167,39 @@ main(int argc, char **argv) handle.time_framesPerSecond = map->map(map->handle, LV2_TIME__framesPerSecond); handle.time_speed = map->map(map->handle, LV2_TIME__speed); - handle.app_driver.map = map; - handle.app_driver.unmap = unmap; - handle.app_driver.log_printf = _log_printf; - handle.app_driver.log_vprintf = _log_vprintf; -#if defined(BUILD_UI) - handle.app_driver.to_ui_request = _app_to_ui_request; - handle.app_driver.to_ui_advance = _app_to_ui_advance; -#else - handle.app_driver.to_ui_request = NULL; - handle.app_driver.to_ui_advance = NULL; -#endif - handle.app_driver.to_worker_request = _app_to_worker_request; - handle.app_driver.to_worker_advance = _app_to_worker_advance; - handle.app_driver.to_app_request = _worker_to_app_request; - handle.app_driver.to_app_advance = _worker_to_app_advance; - handle.app_driver.system_port_add = _system_port_add; - handle.app_driver.system_port_del = _system_port_del; + bin->app_driver.system_port_add = _system_port_add; + bin->app_driver.system_port_del = _system_port_del; #if defined(JACK_HAS_CYCLE_TIMES) handle.osc_sched.osc2frames = _osc_schedule_osc2frames; handle.osc_sched.frames2osc = _osc_schedule_frames2osc; handle.osc_sched.handle = &handle; - handle.app_driver.osc_sched = &handle.osc_sched; + bin->app_driver.osc_sched = &handle.osc_sched; #else - handle.app_driver.osc_sched = NULL; + bin->app_driver.osc_sched = NULL; #endif #if defined(BUILD_UI) - handle.ui_driver.map = map; - handle.ui_driver.unmap = unmap; - handle.ui_driver.to_app_request = _ui_to_app_request; - handle.ui_driver.to_app_advance = _ui_to_app_advance; - handle.ui_driver.opened = _ui_opened; - handle.ui_driver.saved = _ui_saved; - handle.ui_driver.close = _ui_close; - handle.ui_driver.instance_access = 1; // enabled - handle.ui_driver.features = SP_UI_FEATURE_NEW | SP_UI_FEATURE_SAVE | SP_UI_FEATURE_CLOSE; + bin->ui_driver.saved = _ui_saved; + + bin->ui_driver.features = SP_UI_FEATURE_NEW | SP_UI_FEATURE_SAVE | SP_UI_FEATURE_CLOSE; if(synthpod_nsm_managed() || handle.session_id) - handle.ui_driver.features |= SP_UI_FEATURE_IMPORT_FROM | SP_UI_FEATURE_EXPORT_TO; + bin->ui_driver.features |= SP_UI_FEATURE_IMPORT_FROM | SP_UI_FEATURE_EXPORT_TO; else - handle.ui_driver.features |= SP_UI_FEATURE_OPEN | SP_UI_FEATURE_SAVE_AS; - - // create main window - handle.ui_anim = ecore_animator_add(_ui_animator, &handle); - handle.win = elm_win_util_standard_add("synthpod", "Synthpod"); - evas_object_smart_callback_add(handle.win, "delete,request", _ui_delete_request, &handle); - evas_object_resize(handle.win, 1280, 720); - evas_object_show(handle.win); - - // ui init - handle.ui = sp_ui_new(handle.win, NULL, &handle.ui_driver, &handle, 1); + bin->ui_driver.features |= SP_UI_FEATURE_OPEN | SP_UI_FEATURE_SAVE_AS; #endif - // NSM init - const char *exe = strrchr(argv[0], '/'); - exe = exe ? exe + 1 : argv[0]; // we only want the program name without path - handle.nsm = synthpod_nsm_new(exe, argv[optind], &nsm_driver, &handle); //TODO check - - // init semaphores - eina_semaphore_new(&handle.worker_sem, 0); - - // threads init - Eina_Bool status = eina_thread_create(&handle.worker_thread, - EINA_THREAD_URGENT, -1, _worker_thread, &handle); //TODO - -#if defined(BUILD_UI) - // main loop - elm_run(); - - // ui deinit - sp_ui_free(handle.ui); - - evas_object_del(handle.win); - ecore_animator_del(handle.ui_anim); -#else - handle.sig = ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, _quit, &handle); - - ecore_main_loop_begin(); - - ecore_event_handler_del(handle.sig); -#endif // BUILD_UI - - // threads deinit - handle.worker_dead = 1; // atomic operation - eina_semaphore_release(&handle.worker_sem, 1); - eina_thread_join(handle.worker_thread); + // run + bin_run(bin, argv, &nsm_driver); - // NSM deinit - synthpod_nsm_free(handle.nsm); - - // deinit semaphores - eina_semaphore_free(&handle.worker_sem); - - if(handle.path) - free(handle.path); + // stop + bin_stop(bin); // deinit JACK _jack_deinit(&handle); - // synthpod deinit - sp_app_free(handle.app); - - // ext_urid deinit - ext_urid_free(handle.ext_urid); - - // varchunk deinit -#if defined(BUILD_UI) - varchunk_free(handle.app_to_ui); - varchunk_free(handle.app_from_ui); -#endif - varchunk_free(handle.app_to_log); - varchunk_free(handle.app_to_worker); - varchunk_free(handle.app_from_worker); + // deinit + bin_deinit(bin); return 0; } diff --git a/bin/synthpod_pa.c b/bin/synthpod_pa.c deleted file mode 100644 index 758e6283..00000000 --- a/bin/synthpod_pa.c +++ /dev/null @@ -1,653 +0,0 @@ -/* - * Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch) - * - * This is free software: you can redistribute it and/or modify - * it under the terms of the Artistic License 2.0 as published by - * The Perl Foundation. - * - * This source is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Artistic License 2.0 for more details. - * - * You should have received a copy of the Artistic License 2.0 - * along the source as a COPYING file. If not, obtain it from - * http://www.perlfoundation.org/artistic_license_2_0. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> - -#include <synthpod_app.h> -#if defined(BUILD_UI) -# include <synthpod_ui.h> -#else -# include <Ecore.h> -# include <Ecore_File.h> -#endif -#include <ext_urid.h> -#include <varchunk.h> - -#include <synthpod_nsm.h> - -#include <lv2/lv2plug.in/ns/ext/atom/atom.h> -#include <lv2/lv2plug.in/ns/ext/atom/forge.h> -#include <lv2/lv2plug.in/ns/ext/midi/midi.h> -#include <lv2/lv2plug.in/ns/ext/urid/urid.h> -#include <lv2/lv2plug.in/ns/ext/worker/worker.h> -#include <lv2/lv2plug.in/ns/ext/state/state.h> -#include <lv2/lv2plug.in/ns/ext/log/log.h> - -#include <portaudio.h> - -#include <Eina.h> - -#define CHUNK_SIZE 0x10000 -#define SEQ_SIZE 0x2000 - -typedef struct _prog_t prog_t; - -struct _prog_t { - ext_urid_t *ext_urid; - - sp_app_t *app; - sp_app_driver_t app_driver; - - varchunk_t *app_to_worker; - varchunk_t *app_from_worker; - - varchunk_t *app_to_log; - - char *path; - synthpod_nsm_t *nsm; - -#if defined(BUILD_UI) - sp_ui_t *ui; - sp_ui_driver_t ui_driver; - - varchunk_t *app_to_ui; - varchunk_t *app_from_ui; - - varchunk_t *ui_to_app; - varchunk_t *ui_from_app; - - Ecore_Animator *ui_anim; - Evas_Object *win; -#else - Ecore_Event_Handler *sig; -#endif - - LV2_Atom_Forge forge; - - LV2_URID synthpod_json; - LV2_URID midi_MidiEvent; - - LV2_URID log_entry; - LV2_URID log_error; - LV2_URID log_note; - LV2_URID log_trace; - LV2_URID log_warning; - - PaStream *stream; - PaStreamParameters input_params; - PaStreamParameters output_params; - uint32_t sample_rate; - uint32_t min_block_size; - uint32_t max_block_size; - - volatile int worker_dead; - Eina_Thread worker_thread; - Eina_Semaphore worker_sem; -}; - -static const synthpod_nsm_driver_t nsm_driver; // forwared-declaration - -static int -_process(const void *inputs, void *outputs, unsigned long nsamples, - const PaStreamCallbackTimeInfo *time_info, - PaStreamCallbackFlags status_flags, - void *data); // forward-declaration - -static int -_pa_init(prog_t *handle, const char *id) -{ - int num_in = 2; //TODO - int num_out = 2; //TODO - uint32_t sample_rate = 48000; //TODO - uint32_t block_size = 64; //TODO - - // portaudio init - if(Pa_Initialize() != paNoError) - fprintf(stderr, "Pa_Initialize failed\n"); - for(int d=0; d<Pa_GetDeviceCount(); d++) - { - //TODO fill a device list with this - const PaDeviceInfo *info = Pa_GetDeviceInfo(d); - printf("device: %i\n", d); - printf("\tname: %s\n", info->name); - - handle->input_params.device = d; - handle->input_params.channelCount = num_in; - handle->input_params.sampleFormat = paFloat32 | paNonInterleaved; - handle->input_params.suggestedLatency = Pa_GetDeviceInfo(d)->defaultLowInputLatency ; - handle->input_params.hostApiSpecificStreamInfo = NULL; - - handle->output_params.device = d; - handle->output_params.channelCount = num_out; - handle->output_params.sampleFormat = paFloat32 | paNonInterleaved; - handle->output_params.suggestedLatency = Pa_GetDeviceInfo(d)->defaultLowInputLatency ; - handle->output_params.hostApiSpecificStreamInfo = NULL; - - // open first device that supports num_in, num_out @sample_rate - if(Pa_IsFormatSupported(&handle->input_params, &handle->output_params, sample_rate) - == paFormatIsSupported) - { - printf("\tsupported: OK\n"); - - handle->sample_rate = sample_rate; - handle->min_block_size = block_size; - handle->max_block_size = block_size; - - if(Pa_OpenStream(&handle->stream, &handle->input_params, &handle->output_params, - sample_rate, block_size, paNoFlag, _process, handle) != paNoError) - { - fprintf(stderr, "Pa_OpenStream failed\n"); - } - else - return 0; - } - } - - return -1; -} - -static void -_pa_deinit(prog_t *handle) -{ - // portaudio deinit - if(Pa_StopStream(handle->stream) != paNoError) - fprintf(stderr, "Pa_StopStream failed\n"); - if(Pa_CloseStream(handle->stream) != paNoError) - fprintf(stderr, "Pa_CloseStream failed\n"); - if(Pa_Terminate() != paNoError) - fprintf(stderr, "Pa_Terminate failed\n"); -} - -// non-rt worker-thread -static void * -_worker_thread(void *data, Eina_Thread thread) -{ - prog_t *handle = data; - - while(!handle->worker_dead) - { - eina_semaphore_lock(&handle->worker_sem); - - size_t size; - const void *body; - while((body = varchunk_read_request(handle->app_to_worker, &size))) - { - sp_worker_from_app(handle->app, size, body); - varchunk_read_advance(handle->app_to_worker); - } - - const char *trace; - while((trace = varchunk_read_request(handle->app_to_log, &size))) - { - fprintf(stderr, "[Trace] %s\n", trace); - - varchunk_read_advance(handle->app_to_log); - } - } - - return NULL; -} - -#if defined(BUILD_UI) -// non-rt ui-thread -static void -_ui_delete_request(void *data, Evas_Object *obj, void *event) -{ - prog_t *handle = data; - - elm_exit(); -} - -// non-rt ui-thread -static Eina_Bool -_ui_animator(void *data) -{ - prog_t *handle = data; - - size_t size; - const LV2_Atom *atom; - while((atom = varchunk_read_request(handle->app_to_ui, &size))) - { - sp_ui_from_app(handle->ui, atom); - varchunk_read_advance(handle->app_to_ui); - } - - return EINA_TRUE; // continue animator -} -#else -static Eina_Bool -_quit(void *data, int type, void *info) -{ - prog_t *handle = data; - - ecore_main_loop_quit(); - - return EINA_TRUE; -} -#endif // BUILD_UI - -// rt -static int -_process(const void *inputs, void *outputs, unsigned long nsamples, - const PaStreamCallbackTimeInfo *time_info, - PaStreamCallbackFlags status_flags, - void *data) -{ - prog_t *handle = data; - sp_app_t *app = handle->app; - - const void *midi_in_buf = NULL; - float *const *audio_in_buf = inputs; - void *midi_out_buf = NULL; - float **audio_out_buf = outputs; - - const size_t sample_buf_size = sizeof(float) * nsamples; - - //FIXME - - // read events from worker - { - size_t size; - const void *body; - while((body = varchunk_read_request(handle->app_from_worker, &size))) - { - sp_app_from_worker(handle->app, size, body); - varchunk_read_advance(handle->app_from_worker); - } - } - - // run synthpod app pre - sp_app_run_pre(handle->app, nsamples); - -#if defined(BUILD_UI) - // read events from UI - { - size_t size; - const LV2_Atom *atom; - while((atom = varchunk_read_request(handle->app_from_ui, &size))) - { - sp_app_from_ui(handle->app, atom); - varchunk_read_advance(handle->app_from_ui); - } - } -#endif // BUILD_UI - - // run synthpod app post - sp_app_run_post(handle->app, nsamples); - - //FIXME - - return 0; -} - -#if defined(BUILD_UI) -// rt -static void * -_app_to_ui_request(size_t size, void *data) -{ - prog_t *handle = data; - - return varchunk_write_request(handle->app_to_ui, size); -} -static void -_app_to_ui_advance(size_t size, void *data) -{ - prog_t *handle = data; - - varchunk_write_advance(handle->app_to_ui, size); -} - -// non-rt ui-thread -static void * -_ui_to_app_request(size_t size, void *data) -{ - prog_t *handle = data; - - void *ptr; - do - ptr = varchunk_write_request(handle->app_from_ui, size); - while(!ptr); // wait until there is enough space - - return ptr; -} -static void -_ui_to_app_advance(size_t size, void *data) -{ - prog_t *handle = data; - - varchunk_write_advance(handle->app_from_ui, size); -} - -static void -_ui_opened(void *data, int status) -{ - prog_t *handle = data; - - //printf("_ui_opened: %i\n", status); - synthpod_nsm_opened(handle->nsm, status); -} -static void -_ui_saved(void *data, int status) -{ - prog_t *handle = data; - - //printf("_ui_saved: %i\n", status); - synthpod_nsm_saved(handle->nsm, status); -} -static void -_ui_close(void *data) -{ - prog_t *handle = data; - - //printf("_ui_close\n"); - elm_exit(); -} -#endif // BUILD_UI - -// rt -static void * -_app_to_worker_request(size_t size, void *data) -{ - prog_t *handle = data; - - return varchunk_write_request(handle->app_to_worker, size); -} -static void -_app_to_worker_advance(size_t size, void *data) -{ - prog_t *handle = data; - - varchunk_write_advance(handle->app_to_worker, size); - eina_semaphore_release(&handle->worker_sem, 1); -} - -// non-rt worker-thread -static void * -_worker_to_app_request(size_t size, void *data) -{ - prog_t *handle = data; - - void *ptr; - do - ptr = varchunk_write_request(handle->app_from_worker, size); - while(!ptr); // wait until there is enough space - - return ptr; -} -static void -_worker_to_app_advance(size_t size, void *data) -{ - prog_t *handle = data; - - varchunk_write_advance(handle->app_from_worker, size); -} - -// non-rt || rt with LV2_LOG__Trace -static int -_log_vprintf(void *data, LV2_URID type, const char *fmt, va_list args) -{ - prog_t *handle = data; - - if(type == handle->log_trace) - { - char *trace; - if((trace = varchunk_write_request(handle->app_to_log, 1024))) - { - vsprintf(trace, fmt, args); - - size_t written = strlen(trace) + 1; - varchunk_write_advance(handle->app_to_log, written); - eina_semaphore_release(&handle->worker_sem, 1); - } - } - else // !log_trace - { - const char *type_str = NULL; - if(type == handle->log_entry) - type_str = "Entry"; - else if(type == handle->log_error) - type_str = "Error"; - else if(type == handle->log_note) - type_str = "Note"; - else if(type == handle->log_warning) - type_str = "Warning"; - - //TODO send to UI? - - fprintf(stderr, "[%s] ", type_str); - vfprintf(stderr, fmt, args); - fputc('\n', stderr); - - return 0; - } - - return -1; -} - -// non-rt || rt with LV2_LOG__Trace -static int -_log_printf(void *data, LV2_URID type, const char *fmt, ...) -{ - va_list args; - int ret; - - va_start (args, fmt); - ret = _log_vprintf(data, type, fmt, args); - va_end(args); - - return ret; -} - -static int -_open(const char *path, const char *name, const char *id, void *data) -{ - (void)name; - prog_t *handle = data; - - if(handle->path) - free(handle->path); - handle->path = strdup(path); - - // jack init - if(_pa_init(handle, id)) - return -1; - - // synthpod init - handle->app_driver.sample_rate = handle->sample_rate; - handle->app_driver.min_block_size = handle->min_block_size; - handle->app_driver.max_block_size = handle->max_block_size; - handle->app_driver.seq_size = SEQ_SIZE; //TODO - - // app init -#if defined(BUILD_UI) - handle->app = sp_app_new(NULL, &handle->app_driver, handle); -#else //FIXME - handle->app = sp_app_new(NULL, &handle->app_driver, handle); -#endif - - // pa activate - if(Pa_StartStream(handle->stream) != paNoError) - fprintf(stderr, "Pa_StartStream failed\n"); - -#if defined(BUILD_UI) //FIXME - sp_ui_bundle_load(handle->ui, handle->path, 1); -#endif - - return 0; // success -} - -static int -_save(void *data) -{ - prog_t *handle = data; - -#if defined(BUILD_UI) //FIXME - sp_ui_bundle_save(handle->ui, handle->path, 1); -#endif - - return 0; // success -} - -static const synthpod_nsm_driver_t nsm_driver = { - .open = _open, - .save = _save -}; - -#if defined(BUILD_UI) -EAPI_MAIN int -elm_main(int argc, char **argv) -#else -int -main(int argc, char **argv) -#endif -{ - static prog_t handle; - - // varchunk init -#if defined(BUILD_UI) - handle.app_to_ui = varchunk_new(CHUNK_SIZE); - handle.app_from_ui = varchunk_new(CHUNK_SIZE); -#endif - handle.app_to_worker = varchunk_new(CHUNK_SIZE); - handle.app_from_worker = varchunk_new(CHUNK_SIZE); - - handle.app_to_log = varchunk_new(CHUNK_SIZE); - - // ext_urid init - handle.ext_urid = ext_urid_new(); - LV2_URID_Map *map = ext_urid_map_get(handle.ext_urid); - LV2_URID_Unmap *unmap = ext_urid_unmap_get(handle.ext_urid); - - lv2_atom_forge_init(&handle.forge, map); - - handle.synthpod_json = map->map(map->handle, SYNTHPOD_PREFIX"json"); - - handle.midi_MidiEvent = map->map(map->handle, LV2_MIDI__MidiEvent); - - handle.log_entry = map->map(map->handle, LV2_LOG__Entry); - handle.log_error = map->map(map->handle, LV2_LOG__Error); - handle.log_note = map->map(map->handle, LV2_LOG__Note); - handle.log_trace = map->map(map->handle, LV2_LOG__Trace); - handle.log_warning = map->map(map->handle, LV2_LOG__Warning); - - handle.app_driver.map = map; - handle.app_driver.unmap = unmap; - handle.app_driver.log_printf = _log_printf; - handle.app_driver.log_vprintf = _log_vprintf; -#if defined(BUILD_UI) - handle.app_driver.to_ui_request = _app_to_ui_request; - handle.app_driver.to_ui_advance = _app_to_ui_advance; -#else - handle.app_driver.to_ui_request = NULL; - handle.app_driver.to_ui_advance = NULL; -#endif - handle.app_driver.to_worker_request = _app_to_worker_request; - handle.app_driver.to_worker_advance = _app_to_worker_advance; - handle.app_driver.to_app_request = _worker_to_app_request; - handle.app_driver.to_app_advance = _worker_to_app_advance; - handle.app_driver.system_port_add = NULL; //FIXME - handle.app_driver.system_port_del = NULL; //FIXME - -#if defined(BUILD_UI) - handle.ui_driver.map = map; - handle.ui_driver.unmap = unmap; - handle.ui_driver.to_app_request = _ui_to_app_request; - handle.ui_driver.to_app_advance = _ui_to_app_advance; - handle.ui_driver.opened = _ui_opened; - handle.ui_driver.saved = _ui_saved; - handle.ui_driver.close = _ui_close; - handle.ui_driver.instance_access = 1; // enabled - - // create main window - handle.ui_anim = ecore_animator_add(_ui_animator, &handle); - handle.win = elm_win_util_standard_add("synthpod", "Synthpod"); - evas_object_smart_callback_add(handle.win, "delete,request", _ui_delete_request, &handle); - evas_object_resize(handle.win, 1280, 720); - evas_object_show(handle.win); - - // ui init - handle.ui = sp_ui_new(handle.win, NULL, &handle.ui_driver, &handle, 1); -#endif - - // NSM init - handle.nsm = synthpod_nsm_new(argv[0], argc > 1 ? argv[1] : NULL, - &nsm_driver, &handle); //TODO check - - // init semaphores - eina_semaphore_new(&handle.worker_sem, 0); - - // threads init - Eina_Bool status = eina_thread_create(&handle.worker_thread, - EINA_THREAD_URGENT, -1, _worker_thread, &handle); //TODO - -#if defined(BUILD_UI) - // main loop - elm_run(); - - // ui deinit - sp_ui_free(handle.ui); - - evas_object_del(handle.win); - ecore_animator_del(handle.ui_anim); -#else - handle.sig = ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, _quit, &handle); - - ecore_main_loop_begin(); - - ecore_event_handler_del(handle.sig); -#endif // BUILD_UI - - // threads deinit - handle.worker_dead = 1; // atomic operation - eina_semaphore_release(&handle.worker_sem, 1); - eina_thread_join(handle.worker_thread); - - // NSM deinit - synthpod_nsm_free(handle.nsm); - - // deinit semaphores - eina_semaphore_free(&handle.worker_sem); - - if(handle.path) - free(handle.path); - - // deinit PA - _pa_deinit(&handle); - - // synthpod deinit - sp_app_free(handle.app); - - // ext_urid deinit - ext_urid_free(handle.ext_urid); - - // varchunk deinit -#if defined(BUILD_UI) - varchunk_free(handle.app_to_ui); - varchunk_free(handle.app_from_ui); -#endif - varchunk_free(handle.app_to_log); - varchunk_free(handle.app_to_worker); - varchunk_free(handle.app_from_worker); - - return 0; -} - -#if defined(BUILD_UI) -ELM_MAIN() -#endif diff --git a/bin/synthpod_pa.desktop.in b/bin/synthpod_pa.desktop.in deleted file mode 100644 index 37af3bce..00000000 --- a/bin/synthpod_pa.desktop.in +++ /dev/null @@ -1,8 +0,0 @@ -[Desktop Entry] -Name=Synthpod (PortAudio) -Comment=Lightweight, nonlinear LV2 plugin host -Exec=@CMAKE_INSTALL_PREFIX@/@SYNTHPOD_BIN_DIR@/synthpod_pa -Terminal=false -Icon=@CMAKE_INSTALL_PREFIX@/@SYNTHPOD_ICON_DIR@/synthpod.png -Type=Application -Categories=AudioVideo;Audio; diff --git a/bin/synthpod_rtaudio.cpp b/bin/synthpod_rtaudio.cpp deleted file mode 100644 index 0b5b5cc6..00000000 --- a/bin/synthpod_rtaudio.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch) - * - * This is free software: you can redistribute it and/or modify - * it under the terms of the Artistic License 2.0 as published by - * The Perl Foundation. - * - * This source is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Artistic License 2.0 for more details. - * - * You should have received a copy of the Artistic License 2.0 - * along the source as a COPYING file. If not, obtain it from - * http://www.perlfoundation.org/artistic_license_2_0. - */ - -#include <RtAudio.h> - -//#include <synthpod_app.h> -//#include <synthpod_ui.h> -//#include <synthpod_nsm.h> -//#include <ext_urid.h> - -int -main(int argc, char **argv) -{ - - return 0; -} diff --git a/bin/synthpod_rtaudio.desktop.in b/bin/synthpod_rtaudio.desktop.in deleted file mode 100644 index 50f98aef..00000000 --- a/bin/synthpod_rtaudio.desktop.in +++ /dev/null @@ -1,8 +0,0 @@ -[Desktop Entry] -Name=Synthpod (RtAudio) -Comment=Lightweight, nonlinear LV2 plugin host -Exec=@CMAKE_INSTALL_PREFIX@/@SYNTHPOD_BIN_DIR@/synthpod_rtaudio -Terminal=false -Icon=@CMAKE_INSTALL_PREFIX@/@SYNTHPOD_ICON_DIR@/synthpod.png -Type=Application -Categories=AudioVideo;Audio; diff --git a/lib/synthpod_app.c b/lib/synthpod_app.c index 08e62b48..64461947 100644 --- a/lib/synthpod_app.c +++ b/lib/synthpod_app.c @@ -2316,9 +2316,9 @@ sp_app_run_pre(sp_app_t *app, uint32_t nsamples) mod->worker.iface->end_run(mod->handle); // clear atom sequence input buffers - for(int i=0; i<mod->num_ports; i++) + for(int p=0; p<mod->num_ports; p++) { - port_t *port = &mod->ports[i]; + port_t *port = &mod->ports[p]; if(port->direction == PORT_DIRECTION_INPUT) // ignore output ports { @@ -2404,9 +2404,9 @@ sp_app_run_post(sp_app_t *app, uint32_t nsamples) } // multiplex multiple sources to single sink where needed - for(int i=0; i<mod->num_ports; i++) + for(int p=0; p<mod->num_ports; p++) { - port_t *port = &mod->ports[i]; + port_t *port = &mod->ports[p]; if(port->direction == PORT_DIRECTION_OUTPUT) continue; // not a sink @@ -2417,9 +2417,9 @@ sp_app_run_post(sp_app_t *app, uint32_t nsamples) { float *val = PORT_BUF_ALIGNED(port); *val = 0; // init - for(int i=0; i<port->num_sources; i++) + for(int s=0; s<port->num_sources; s++) { - float *src = PORT_BUF_ALIGNED(port->sources[i].port); + float *src = PORT_BUF_ALIGNED(port->sources[s].port); *val += *src; } } @@ -2428,9 +2428,9 @@ sp_app_run_post(sp_app_t *app, uint32_t nsamples) { float *val = PORT_BUF_ALIGNED(port); memset(val, 0, nsamples * sizeof(float)); // init - for(int i=0; i<port->num_sources; i++) + for(int s=0; s<port->num_sources; s++) { - source_t *source = &port->sources[i]; + source_t *source = &port->sources[s]; // ramp audio output ports if(source->ramp.state != RAMP_STATE_NONE) @@ -2460,10 +2460,10 @@ sp_app_run_post(sp_app_t *app, uint32_t nsamples) LV2_Atom_Sequence *seq [32]; //TODO how big? LV2_Atom_Event *itr [32]; //TODO how big? - for(int i=0; i<port->num_sources; i++) + for(int s=0; s<port->num_sources; s++) { - seq[i] = PORT_BUF_ALIGNED(port->sources[i].port); - itr[i] = lv2_atom_sequence_begin(&seq[i]->body); + seq[s] = PORT_BUF_ALIGNED(port->sources[s].port); + itr[s] = lv2_atom_sequence_begin(&seq[s]->body); } while(1) @@ -2472,15 +2472,15 @@ sp_app_run_post(sp_app_t *app, uint32_t nsamples) int64_t frames = nsamples; // search for next event in timeline accross source ports - for(i=0; i<port->num_sources; i++) + for(int s=0; s<port->num_sources; s++) { - if(lv2_atom_sequence_is_end(&seq[i]->body, seq[i]->atom.size, itr[i])) + if(lv2_atom_sequence_is_end(&seq[s]->body, seq[s]->atom.size, itr[s])) continue; // reached sequence end - if(itr[i]->time.frames < frames) + if(itr[s]->time.frames < frames) { - frames = itr[i]->time.frames; - nxt = i; + frames = itr[s]->time.frames; + nxt = s; } } |