clip save implemented, fixes #121

This commit is contained in:
Harry van Haaren 2016-11-03 20:09:06 +00:00
parent e5e57d7a74
commit 5acf1f33d6
9 changed files with 121 additions and 28 deletions

View file

@ -19,6 +19,8 @@
#include "clipselector.hxx"
#include <unistd.h>
#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 );

View file

@ -308,14 +308,16 @@ 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 )
{
LUPPP_WARN("%s", "Session folders not created yet, while trying to write audioBuffers.");
return LUPPP_RETURN_ERROR;
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";
@ -334,8 +336,14 @@ int DiskWriter::writeAudioBuffer(int track, int scene, AudioBuffer* ab )
// write the AudioBuffer contents to <path>/audio/ as <name>.wav
// or alternatively t_<track>_s_<scene>.wav
stringstream path;
path << audioDir << "/" << filename.str();
}
else
{
LUPPP_WARN("%s", "Session folders not created yet, while trying to write audioBuffers.");
return LUPPP_RETURN_ERROR;
}
SndfileHandle outfile( path.str(), SFM_WRITE, SF_FORMAT_WAV | SF_FORMAT_FLOAT, 1, gui->samplerate );

View file

@ -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();

View file

@ -663,8 +663,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) {}
};

View file

@ -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: {

View file

@ -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
// 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: {

View file

@ -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

View file

@ -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*);
@ -92,6 +94,8 @@ class Gui
int specialTrack;
int specialScene;
// save a particular sample to path
std::string saveBufferPath;
private:
vector<std::string> controllerVector;

View file

@ -83,6 +83,8 @@ class LooperClip : public Stately
long getActualAudioLength();
size_t audioBufferSize();
AudioBuffer* getAudioBuffer() {return _buffer;}
/// set clip state
void queuePlay(bool=true);
void queueStop();