diff --git a/resources/controllers/akai_apc_key25.ctrl b/resources/controllers/akai_apc_key25.ctrl new file mode 100644 index 0000000..e41781d --- /dev/null +++ b/resources/controllers/akai_apc_key25.ctrl @@ -0,0 +1,947 @@ +{ + "name": "AKAI_APCkey25", + "author": "Romain Caneill", + "link": "", + "inputBindings": [{ + " __COMMMENT__ ###############################" : "track 0", + "action": "grid:event", + "status": 144, + "data": 32, + "track": 0, + "scene": 0 + }, + { + "action": "grid:event", + "status": 144, + "data": 24, + "track": 0, + "scene": 1 + }, + { + "action": "grid:event", + "status": 144, + "data": 16, + "track": 0, + "scene": 2 + }, + { + "action": "grid:event", + "status": 144, + "data": 8, + "track": 0, + "scene": 3 + }, + { + "action": "grid:event", + "status": 144, + "data": 0, + "track": 0, + "scene": 4 + }, + { + "action": "track:volume", + "status": 176, + "data": 48, + "track": 0, + "send": 1, + "active": 0 + }, + { + "action": "track:send_active", + "status": 144, + "data": 64, + "track": 0, + "send": 0, + "active": 1 + }, + { + "action": "track:send_active", + "status": 128, + "data": 64, + "track": 0, + "send": 0, + "active": 0 + }, + { + " __COMMMENT__ ###############################" : "track 1", + "action": "grid:event", + "status": 144, + "data": 33, + "track": 1, + "scene": 0 + }, + { + "action": "grid:event", + "status": 144, + "data": 25, + "track": 1, + "scene": 1 + }, + { + "action": "grid:event", + "status": 144, + "data": 17, + "track": 1, + "scene": 2 + }, + { + "action": "grid:event", + "status": 144, + "data": 9, + "track": 1, + "scene": 3 + }, + { + "action": "grid:event", + "status": 144, + "data": 1, + "track": 1, + "scene": 4 + }, + { + "action": "track:volume", + "status": 176, + "data": 49, + "track": 1 + }, + { + "action": "track:send_active", + "status": 144, + "data": 65, + "track": 1, + "send": 0, + "active": 1 + }, + { + "action": "track:send_active", + "status": 128, + "data": 65, + "track": 1, + "send": 0, + "active": 0 + }, + { + " __COMMMENT__ ###############################" : "track 2", + "action": "grid:event", + "status": 144, + "data": 34, + "track": 2, + "scene": 0 + }, + { + "action": "grid:event", + "status": 144, + "data": 26, + "track": 2, + "scene": 1 + }, + { + "action": "grid:event", + "status": 144, + "data": 18, + "track": 2, + "scene": 2 + }, + { + "action": "grid:event", + "status": 144, + "data": 10, + "track": 2, + "scene": 3 + }, + { + "action": "grid:event", + "status": 144, + "data": 2, + "track": 2, + "scene": 4 + }, + { + "action": "track:volume", + "status": 176, + "data": 50, + "track": 2 + }, + { + "action": "track:send_active", + "status": 144, + "data": 66, + "track": 2, + "send": 0, + "active": 1 + }, + { + "action": "track:send_active", + "status": 128, + "data": 66, + "track": 2, + "send": 0, + "active": 0 + }, + { + " __COMMMENT__ ###############################" : "track 3", + "action": "grid:event", + "status": 144, + "data": 35, + "track": 3, + "scene": 0 + }, + { + "action": "grid:event", + "status": 144, + "data": 27, + "track": 3, + "scene": 1 + }, + { + "action": "grid:event", + "status": 144, + "data": 19, + "track": 3, + "scene": 2 + }, + { + "action": "grid:event", + "status": 144, + "data": 11, + "track": 3, + "scene": 3 + }, + { + "action": "grid:event", + "status": 144, + "data": 3, + "track": 3, + "scene": 4 + }, + { + "action": "track:volume", + "status": 176, + "data": 51, + "track": 3 + }, + { + "action": "track:send_active", + "status": 144, + "data": 67, + "track": 3, + "send": 0, + "active": 1 + }, + { + "action": "track:send_active", + "status": 128, + "data": 67, + "track": 3, + "send": 0, + "active": 0 + }, + { + " __COMMMENT__ ###############################" : "track 4", + "action": "grid:event", + "status": 144, + "data": 36, + "track": 4, + "scene": 0 + }, + { + "action": "grid:event", + "status": 144, + "data": 28, + "track": 4, + "scene": 1 + }, + { + "action": "grid:event", + "status": 144, + "data": 20, + "track": 4, + "scene": 2 + }, + { + "action": "grid:event", + "status": 144, + "data": 12, + "track": 4, + "scene": 3 + }, + { + "action": "grid:event", + "status": 144, + "data": 4, + "track": 4, + "scene": 4 + }, + { + "action": "track:volume", + "status": 176, + "data": 52, + "track": 4 + }, + { + "action": "track:send_active", + "status": 144, + "data": 68, + "track": 4, + "send": 0, + "active": 1 + }, + { + "action": "track:send_active", + "status": 128, + "data": 68, + "track": 4, + "send": 0, + "active": 0 + }, + { + " __COMMMENT__ ###############################" : "track 5", + "action": "grid:event", + "status": 144, + "data": 37, + "track": 5, + "scene": 0 + }, + { + "action": "grid:event", + "status": 144, + "data": 29, + "track": 5, + "scene": 1 + }, + { + "action": "grid:event", + "status": 144, + "data": 21, + "track": 5, + "scene": 2 + }, + { + "action": "grid:event", + "status": 144, + "data": 13, + "track": 5, + "scene": 3 + }, + { + "action": "grid:event", + "status": 144, + "data": 5, + "track": 5, + "scene": 4 + }, + { + "action": "track:volume", + "status": 176, + "data": 53, + "track": 5 + }, + { + "action": "track:send_active", + "status": 144, + "data": 69, + "track": 5, + "send": 0, + "active": 1 + }, + { + "action": "track:send_active", + "status": 128, + "data": 69, + "track": 5, + "send": 0, + "active": 0 + }, + { + " __COMMMENT__ ###############################" : "track 6", + "action": "grid:event", + "status": 144, + "data": 38, + "track": 6, + "scene": 0 + }, + { + "action": "grid:event", + "status": 144, + "data": 30, + "track": 6, + "scene": 1 + }, + { + "action": "grid:event", + "status": 144, + "data": 22, + "track": 6, + "scene": 2 + }, + { + "action": "grid:event", + "status": 144, + "data": 14, + "track": 6, + "scene": 3 + }, + { + "action": "grid:event", + "status": 144, + "data": 6, + "track": 6, + "scene": 4 + }, + { + "action": "track:volume", + "status": 176, + "data": 54, + "track": 6 + }, + { + "action": "track:send_active", + "status": 144, + "data": 70, + "track": 6, + "send": 0, + "active": 1 + }, + { + "action": "track:send_active", + "status": 128, + "data": 70, + "track": 6, + "send": 0, + "active": 0 + }, + { + " __COMMMENT__ ###############################" : "track 7", + "action": "grid:event", + "status": 144, + "data": 39, + "track": 7, + "scene": 0 + }, + { + "action": "grid:event", + "status": 144, + "data": 31, + "track": 7, + "scene": 1 + }, + { + "action": "grid:event", + "status": 144, + "data": 23, + "track": 7, + "scene": 2 + }, + { + "action": "grid:event", + "status": 144, + "data": 15, + "track": 7, + "scene": 3 + }, + { + "action": "grid:event", + "status": 144, + "data": 7, + "track": 7, + "scene": 4 + }, + { + "action": "track:volume", + "status": 176, + "data": 55, + "track": 7 + }, + { + "action": "track:send_active", + "status": 144, + "data": 71, + "track": 7, + "send": 0, + "active": 1 + }, + { + "action": "track:send_active", + "status": 128, + "data": 71, + "track": 7, + "send": 0, + "active": 0 + }, + { + " __COMMMENT__ ###############################" : "lauch scenes", + "action": "grid:launch_scene", + "status": 144, + "data": 82, + "scene": 0 + }, { + "action": "grid:launch_scene", + "status": 144, + "data": 83, + "scene": 1 + }, { + "action": "grid:launch_scene", + "status": 144, + "data": 84, + "scene": 2 + }, { + "action": "grid:launch_scene", + "status": 144, + "data": 85, + "scene": 3 + }, { + "action": "grid:launch_scene", + "status": 144, + "data": 86, + "scene": 4 + }], + + +"outputBindings": [{ + " __COMMMENT__ ###############################" : "track 0", + "action" : "grid:clip_state", + "status" : 144, + "data" : 32, + "track" : 0, + "scene" : 0, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 24, + "track" : 0, + "scene" : 1, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 16, + "track" : 0, + "scene" : 2, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 8, + "track" : 0, + "scene" : 3, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 0, + "track" : 0, + "scene" : 4, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + +{ + " __COMMMENT__ ###############################" : "track 0", + "action" : "grid:clip_state", + "status" : 144, + "data" : 33, + "track" : 1, + "scene" : 0, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 25, + "track" : 1, + "scene" : 1, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 17, + "track" : 1, + "scene" : 2, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 9, + "track" : 1, + "scene" : 3, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 1, + "track" : 1, + "scene" : 4, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + +{ + " __COMMMENT__ ###############################" : "track 0", + "action" : "grid:clip_state", + "status" : 144, + "data" : 34, + "track" : 2, + "scene" : 0, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 26, + "track" : 2, + "scene" : 1, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 18, + "track" : 2, + "scene" : 2, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 10, + "track" : 2, + "scene" : 3, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 2, + "track" : 2, + "scene" : 4, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + +{ + " __COMMMENT__ ###############################" : "track 0", + "action" : "grid:clip_state", + "status" : 144, + "data" : 35, + "track" : 3, + "scene" : 0, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 27, + "track" : 3, + "scene" : 1, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 19, + "track" : 3, + "scene" : 2, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 11, + "track" : 3, + "scene" : 3, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 3, + "track" : 3, + "scene" : 4, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + +{ + " __COMMMENT__ ###############################" : "track 0", + "action" : "grid:clip_state", + "status" : 144, + "data" : 36, + "track" : 4, + "scene" : 0, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 28, + "track" : 4, + "scene" : 1, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 20, + "track" : 4, + "scene" : 2, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 12, + "track" : 4, + "scene" : 3, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 4, + "track" : 4, + "scene" : 4, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + +{ + " __COMMMENT__ ###############################" : "track 0", + "action" : "grid:clip_state", + "status" : 144, + "data" : 37, + "track" : 5, + "scene" : 0, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 29, + "track" : 5, + "scene" : 1, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 21, + "track" : 5, + "scene" : 2, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 13, + "track" : 5, + "scene" : 3, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 5, + "track" : 5, + "scene" : 4, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + +{ + " __COMMMENT__ ###############################" : "track 0", + "action" : "grid:clip_state", + "status" : 144, + "data" : 38, + "track" : 6, + "scene" : 0, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 30, + "track" : 6, + "scene" : 1, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 22, + "track" : 6, + "scene" : 2, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 14, + "track" : 6, + "scene" : 3, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 6, + "track" : 6, + "scene" : 4, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + +{ + " __COMMMENT__ ###############################" : "track 0", + "action" : "grid:clip_state", + "status" : 144, + "data" : 39, + "track" : 7, + "scene" : 0, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 31, + "track" : 7, + "scene" : 1, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 23, + "track" : 7, + "scene" : 2, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 15, + "track" : 7, + "scene" : 3, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }, + { + + "action" : "grid:clip_state", + "status" : 144, + "data" : 7, + "track" : 7, + "scene" : 4, + "state" : { + "empty" : 0, "stopped" : 5, "playing" : 1, "recording" : 3, + "queueStopped" : 6, "queuePlaying" : 2, "queueRecording" : 4} + }] +} diff --git a/src/avtk/clipselector.cxx b/src/avtk/clipselector.cxx index 5b2b64d..b6690b9 100644 --- a/src/avtk/clipselector.cxx +++ b/src/avtk/clipselector.cxx @@ -19,6 +19,8 @@ #include "clipselector.hxx" +#include + #pragma GCC diagnostic ignored "-Wmissing-field-initializers" #include "../gui.hxx" @@ -292,6 +294,7 @@ int ClipSelector::handle(int event) Fl_Menu_Item rclick_menu[] = { { "Load" }, + { "Save" }, { "Special"}, { "Beats", 0, 0, 0, FL_SUBMENU | FL_MENU_DIVIDER }, {"1 "}, @@ -317,6 +320,22 @@ int ClipSelector::handle(int event) { gui->selectLoadSample( ID, clipNum ); } + else if ( strcmp(m->label(), "Save") == 0 ) + { + //gui->saveBufferPath = "/tmp/test.wav"; + char* tmp = gui->selectSavePath(); + if(tmp && strlen(tmp)) { + if( access( tmp, F_OK ) != -1 ) { + int overwrite = fl_choice("Overwrite file?","Cancel","Overwrite",0); + if (!overwrite) { + return 0; + } + } + gui->saveBufferPath = tmp; + free(tmp); + gui->selectSaveSample( ID, clipNum ); + } + } else if ( strcmp(m->label(), "1 ") == 0 ) { EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,1); writeToDspRingbuffer( &e ); diff --git a/src/diskwriter.cxx b/src/diskwriter.cxx index b2afc85..690dc7c 100644 --- a/src/diskwriter.cxx +++ b/src/diskwriter.cxx @@ -308,34 +308,42 @@ int DiskWriter::writeControllerFile( Controller* c ) return LUPPP_RETURN_OK; } -int DiskWriter::writeAudioBuffer(int track, int scene, AudioBuffer* ab ) +int DiskWriter::writeAudioBuffer(int track, int scene, AudioBuffer* ab, + const char *gui_path) { - if ( !foldersCreated ) + stringstream path; + if ( gui_path && strlen(gui_path) ) { + printf("saving single buffer to %s\n", gui_path); + path << gui_path; + } + else if ( foldersCreated ) + { + stringstream filename; + filename << "t_" << track << "_s_" << scene << ".wav"; + + // store the clip in clipData, we will write the session JSON for it in writeSession + clipData.push_back( ClipData( track, scene, filename.str() ) ); + + // add the AudioBuffer metadata to the sample JSON node + cJSON* sampleClip = cJSON_CreateObject(); + cJSON_AddItemToObject(audioJson, filename.str().c_str(), sampleClip ); + cJSON_AddNumberToObject(sampleClip,"beats", ab->getBeats() ); + + // get pretty name from GUI + std::string clipName = gui->getTrack(track)->getClipSelector()->clipName( scene ); + cJSON_AddItemToObject ( sampleClip, "name", cJSON_CreateString( clipName.c_str() )); + + // write the AudioBuffer contents to /audio/ as .wav + // or alternatively t__s_.wav + + path << audioDir << "/" << filename.str(); + } + else { LUPPP_WARN("%s", "Session folders not created yet, while trying to write audioBuffers."); return LUPPP_RETURN_ERROR; } - stringstream filename; - filename << "t_" << track << "_s_" << scene << ".wav"; - - // store the clip in clipData, we will write the session JSON for it in writeSession - clipData.push_back( ClipData( track, scene, filename.str() ) ); - - // add the AudioBuffer metadata to the sample JSON node - cJSON* sampleClip = cJSON_CreateObject(); - cJSON_AddItemToObject(audioJson, filename.str().c_str(), sampleClip ); - cJSON_AddNumberToObject(sampleClip,"beats", ab->getBeats() ); - - // get pretty name from GUI - std::string clipName = gui->getTrack(track)->getClipSelector()->clipName( scene ); - cJSON_AddItemToObject ( sampleClip, "name", cJSON_CreateString( clipName.c_str() )); - - // write the AudioBuffer contents to /audio/ as .wav - // or alternatively t__s_.wav - - stringstream path; - path << audioDir << "/" << filename.str(); SndfileHandle outfile( path.str(), SFM_WRITE, SF_FORMAT_WAV | SF_FORMAT_FLOAT, 1, gui->samplerate ); diff --git a/src/diskwriter.hxx b/src/diskwriter.hxx index 3cc23e7..14c252c 100644 --- a/src/diskwriter.hxx +++ b/src/diskwriter.hxx @@ -59,8 +59,10 @@ class DiskWriter /// sets up session write path etc void initialize( std::string path, std::string sessionName ); - /// writes a single audio buffer to disk - int writeAudioBuffer(int track, int scene, AudioBuffer* ab ); + /// writes a single audio buffer to disk for saving whole state. + // When gui_path is set, it only saves a single AB* to that path + int writeAudioBuffer(int track, int scene, AudioBuffer* ab, + const char* gui_path = 0); /// flush the JSON to disk, finalizing the save int writeSession(); diff --git a/src/event.hxx b/src/event.hxx index 372f3a2..e3efca1 100644 --- a/src/event.hxx +++ b/src/event.hxx @@ -695,8 +695,9 @@ class EventStateSaveBuffer : public EventBase int scene; // pointer to the AudioBuffer to be saved AudioBuffer* ab; + bool no_dealloc; - EventStateSaveBuffer(): track(0), scene(0), ab(0) {} + EventStateSaveBuffer(): track(0), scene(0), ab(0), no_dealloc(0) {} EventStateSaveBuffer(int t, int s, AudioBuffer* a): track(t), scene(s), ab(a) {} }; diff --git a/src/eventhandlerdsp.cxx b/src/eventhandlerdsp.cxx index 25fbb14..9a165b0 100644 --- a/src/eventhandlerdsp.cxx +++ b/src/eventhandlerdsp.cxx @@ -104,6 +104,20 @@ void handleDspEvents() jack_ringbuffer_read( rbToDsp, (char*)&ev, sizeof(EventStateReset) ); jack->getState()->reset(); } break; } + case Event::STATE_SAVE_BUFFER: { + if ( availableRead >= sizeof(EventStateReset) ) { + EventStateSaveBuffer ev; + jack_ringbuffer_read( rbToDsp, (char*)&ev, sizeof(EventStateSaveBuffer) ); + printf("jack got save buffer in %d, %d\n", ev.track, ev.scene); + LooperClip* lc = jack->getLooper(ev.track)->getClip(ev.scene); + if(!lc) break; + EventStateSaveBuffer e; + e.track = ev.track; + e.scene = ev.scene; + e.ab = lc->getAudioBuffer(); + e.no_dealloc = 1; + writeToGuiRingbuffer( &e ); + } break; } // ========= MASTER === case Event::MASTER_VOL: { diff --git a/src/eventhandlergui.cxx b/src/eventhandlergui.cxx index 9336fa0..467cd7b 100644 --- a/src/eventhandlergui.cxx +++ b/src/eventhandlergui.cxx @@ -181,8 +181,17 @@ void handleGuiEvents() cout << "EventSaveBuffer: " << ev.track << " " << ev.scene << " " << ev.ab->getID() << endl; #endif gui->getDiskWriter()->writeAudioBuffer( ev.track, ev.scene, ev.ab ); - // de allocate the AudioBuffer - delete ev.ab; + // de allocate the AudioBuffer only if reqested + if(!ev.no_dealloc) { + gui->getDiskWriter()->writeAudioBuffer( ev.track, ev.scene, ev.ab ); + delete ev.ab; + } else + { + gui->getDiskWriter()->writeAudioBuffer(ev.track, ev.scene, ev.ab, + gui->saveBufferPath.c_str()); + gui->saveBufferPath = ""; + } + } break; } case Event::STATE_SAVE_FINISH: { diff --git a/src/gmastertrack.cxx b/src/gmastertrack.cxx index fb55e9d..35da00b 100644 --- a/src/gmastertrack.cxx +++ b/src/gmastertrack.cxx @@ -194,6 +194,7 @@ static void gmastertrack_button_callback(Fl_Widget *w, void *data) } } +#define OFST 33 GMasterTrack::GMasterTrack(int x, int y, int w, int h, const char* l ) : Fl_Group(x, y, w, h), title( strdup(l) ), @@ -203,14 +204,14 @@ GMasterTrack::GMasterTrack(int x, int y, int w, int h, const char* l ) : clipSel(x + 5, y + 26 + 102, 140, 294,"", true), source(x+5, y+26, 140, 100, ""), - volBox(x+5, y+422, 140, 172, ""), + volBox(x+5, y+422, 140, 232, ""), - transport ( x + w * 2/4.f - 18, y + 426 + 26 * 0, 44,24, "Stop" ), - tapTempo ( x + w * 2/4.f - 18, y + 426 + 26 * 1, 44,24, "Tap" ), - metronomeButton( x + w * 2/4.f - 18, y + 426 + 26 * 2, 44,24,"Metro"), + transport ( x + w * 2/4.f - 18, y + 436 + OFST * 0, 44,28, "Stop" ), + tapTempo ( x + w * 2/4.f - 18, y + 436 + OFST * 1, 44,28, "Tap" ), + metronomeButton( x + w * 2/4.f - 18, y + 436 + OFST * 2, 44,28,"Metro"), - tempoDial ( x + w * 2/4.f - 18, y + 426 + 41 * 2, 45, 36,"BPM"), - returnVol ( x + w * 2/4.f - 18, y + 426 + 41 * 3, 45, 36,"Return"), + tempoDial ( x + w * 2/4.f - 18, y + 436 + OFST * 3.5, 45, 38,"BPM"), + returnVol ( x + w * 2/4.f - 18, y + 436 + OFST * 5, 45, 38,"Return"), inputVolume(x + 9,y + 26 + 4, w - 18, 30,""), @@ -223,7 +224,7 @@ GMasterTrack::GMasterTrack(int x, int y, int w, int h, const char* l ) : inputToMix (x + w*0.8-20,y + 28 + 68, 40, 26,"Mix"), inputToMixVol(x + w*0.8-15,y + 28 + 36, 30, 30,""), - volume(x+106, y +425, 36, 166, "") + volume(x+106, y +425, 36, 216, "") { ID = privateID++; @@ -254,8 +255,6 @@ GMasterTrack::GMasterTrack(int x, int y, int w, int h, const char* l ) : inputToMix.callback ( gmastertrack_mixButton_callback, 0 ); inputToMixVol.callback ( gmastertrack_mixVol_callback, 0 ); - - tempoDial.align( FL_ALIGN_CENTER ); returnVol.value( 1.f ); @@ -264,7 +263,7 @@ GMasterTrack::GMasterTrack(int x, int y, int w, int h, const char* l ) : for(int i = 0; i < 4; i++) { - beatLights[i] = new Avtk::LightButton( x + 11, y + 427 + 41 * i, 38, 38, "" ); + beatLights[i] = new Avtk::LightButton( x + 10, y + 437 + 54 * i, 40, 42, "" ); } beatLights[0]->setColor( 1.0, 0.0 , 0.0 ); beatLights[1]->setColor( 1.0, 0.48, 0.0 ); diff --git a/src/gtrack.cxx b/src/gtrack.cxx index be1a809..751b599 100644 --- a/src/gtrack.cxx +++ b/src/gtrack.cxx @@ -79,6 +79,7 @@ GTrack::GTrack(int x, int y, int w, int h, const char* l ) : jackSendActivate.callback(gtrack_jacksendactivate_cb,this); jackSendDial.align(FL_ALIGN_INSIDE); jackSendDial.callback(gtrack_jacksend_cb,this); + jackSendDial.value(1.0); //volBox.color( fl_rgb_color( 0,0,0 ) ); end(); // close the group diff --git a/src/gui.cxx b/src/gui.cxx index 5582956..7b6a7c4 100644 --- a/src/gui.cxx +++ b/src/gui.cxx @@ -252,6 +252,40 @@ void Gui::selectLoadController(Fl_Widget* w, void*) } +void Gui::selectSaveSample( int track, int scene ) +{ + EventStateSaveBuffer e; + e.track = track, + e.scene = scene, + writeToDspRingbuffer( &e ); +} + +char * +Gui::selectSavePath() +{ + string path; + Fl_Native_File_Chooser fnfc; + fnfc.title("Save filename?"); + fnfc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); + + std::string defLoadPath = gui->getDiskReader()->getLastLoadedSamplePath(); + fnfc.directory( defLoadPath.c_str() ); // default directory to use + + // Show native chooser + switch ( fnfc.show() ) { + case -1: /*printf("ERROR: %s\n", fnfc.errmsg()); */ break; // ERROR + case 1: /*(printf("CANCEL\n"); */ break; // CANCEL + default: /*printf("Loading directory: %s\n", fnfc.filename()); */ + path = fnfc.filename(); + break; + } + + if ( strcmp( path.c_str(), "" ) == 0 ) + return 0; + + return strdup(path.c_str()); +} + void Gui::selectLoadSample( int track, int scene ) { // FIXME: refactor @@ -409,26 +443,14 @@ Gui::Gui(const char* argZero) : // create a new "Group" with all Luppp GUI contents, for resizing lupppGroup = new Fl_Group( 0, 0, 1110, 650, "Luppp"); { - // everything in here will have resize() called when main window is resized - - /* - Fl_Bitmap* headImg = new Fl_Bitmap( (unsigned char*)header.pixel_data, 1110, 36 ); - - Fl_Box* pic_box = new Fl_Box(0,0,1110,36); - pic_box->image( headImg ); - pic_box->redraw(); - */ - int i = 0; for (; i < NTRACKS; i++ ) { stringstream s; s << "Track " << i+1; - //printf("track name %s\n", s.str().c_str() ); tracks.push_back( new GTrack(8 + i * 118, 40, 110, 650, s.str().c_str() ) ); } - - master = new GMasterTrack(8 + i * 118, 40, 150, 600, "Master"); + master = new GMasterTrack(8 + i * 118, 40, 150, 650, "Master"); } lupppGroup->end(); diff --git a/src/gui.hxx b/src/gui.hxx index eaa0764..9a49fd1 100644 --- a/src/gui.hxx +++ b/src/gui.hxx @@ -76,6 +76,8 @@ class Gui /// used to load samples into the grid void selectLoadSample( int track, int clip ); + void selectSaveSample( int track, int clip ); + char* selectSavePath(); /// allows the user to select a Controller definition static void selectLoadController(Fl_Widget* w, void*); @@ -94,7 +96,9 @@ class Gui /// current special clip: int specialTrack; int specialScene; - + + // save a particular sample to path + std::string saveBufferPath; private: vector controllerVector; diff --git a/src/jacksendreturn.cxx b/src/jacksendreturn.cxx index d8feff8..17c078d 100644 --- a/src/jacksendreturn.cxx +++ b/src/jacksendreturn.cxx @@ -4,12 +4,12 @@ #include extern Jack* jack; JackSendReturn::JackSendReturn(int trackid, AudioProcessor *prev, jack_client_t *client) - :m_trackid(trackid), m_previousProcessor(prev) + :m_trackid(trackid), m_previousProcessor(prev), m_sendvol(1.0f) { char name[50]; - sprintf(name, "Send_track_%d\0",trackid); + sprintf(name, "Send_track_%d\n",trackid); m_sendport=jack_port_register(client,name,JACK_DEFAULT_AUDIO_TYPE,JackPortIsOutput,0); - sprintf(name, "Return_track_%d\0",trackid); + sprintf(name, "Return_track_%d\n",trackid); m_returnport=jack_port_register(client,name,JACK_DEFAULT_AUDIO_TYPE,JackPortIsInput,0); m_active=false; m_counter=0; diff --git a/src/looperclip.hxx b/src/looperclip.hxx index 269d6ba..a419ba4 100644 --- a/src/looperclip.hxx +++ b/src/looperclip.hxx @@ -82,6 +82,8 @@ class LooperClip : public Stately //Return the nr of samples holding actual audio. This is less then getBufferLength(); long getActualAudioLength(); size_t audioBufferSize(); + + AudioBuffer* getAudioBuffer() {return _buffer;} /// set clip state void queuePlay(bool=true);