aboutsummaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorHanspeter Portner <dev@open-music-kontrollers.ch>2015-09-11 22:27:55 +0200
committerHanspeter Portner <dev@open-music-kontrollers.ch>2015-09-11 22:27:55 +0200
commit36d29fb13e45b369011d4fd79fb7a06c82e2c873 (patch)
tree0737c1f1b77f8dceb08414da15bfff5cfe72e515 /bin
parent0c9aec8f2f8426eb1a46c3a2485f19d692ffeedc (diff)
downloadsynthpod-36d29fb13e45b369011d4fd79fb7a06c82e2c873.tar.xz
implement synthpod_alsa and commonize code.
* implement synthpod_alsa * commonize code with synthpod_jack
Diffstat (limited to 'bin')
-rw-r--r--bin/CMakeLists.txt75
-rw-r--r--bin/pcmi.cpp8
-rw-r--r--bin/pcmi.h3
-rw-r--r--bin/synthpod_alsa.c556
-rw-r--r--bin/synthpod_bin.h532
-rw-r--r--bin/synthpod_jack.c551
-rw-r--r--bin/synthpod_pa.c653
-rw-r--r--bin/synthpod_pa.desktop.in8
-rw-r--r--bin/synthpod_rtaudio.cpp30
-rw-r--r--bin/synthpod_rtaudio.desktop.in8
10 files changed, 1094 insertions, 1330 deletions
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;
diff --git a/bin/pcmi.h b/bin/pcmi.h
index d16e5b38..98abf133 100644
--- a/bin/pcmi.h
+++ b/bin/pcmi.h
@@ -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;