diff --git a/src/audiobuffer.hxx b/src/audiobuffer.hxx new file mode 100644 index 0000000..4e7ea5d --- /dev/null +++ b/src/audiobuffer.hxx @@ -0,0 +1,54 @@ + +#ifndef LUPPP_AUDIOBUFFER_H +#define LUPPP_AUDIOBUFFER_H + +// System +#include + +// AudioBuffer stores float samples in a big vector. The vector can be +// accessed only by const reference, so its state is immutable +class AudioBuffer +{ + public: + AudioBuffer() + { + ID = privateID++; + } + ~AudioBuffer(); + + int getID() + { + return ID; + } + + int getBeats() + { + return numBeats; + } + + void setBeats(int b) + { + numBeats = b; + } + + std::vector& get() + { + return buffer; + } + + void nonRtSetSample(std::vector& sample) + { + buffer.swap(sample); + } + + protected: + static int privateID; + int ID; + + int numBeats; + + std::vector buffer; +}; + +#endif + diff --git a/src/event.hxx b/src/event.hxx index 5460928..f8a677a 100644 --- a/src/event.hxx +++ b/src/event.hxx @@ -21,6 +21,7 @@ namespace Event MASTER_VOL, RECORD, + LOOPER_LOAD, LOOPER_STATE, LOOPER_PROGRESS, LOOPER_LOOP_LENGTH, @@ -96,18 +97,18 @@ class EventLooperLoopLength : public EventBase EventLooperLoopLength(int t, float s) : track(t), scale(s){} }; -class EventLoadSample : public EventBase +class EventLooperLoad : public EventBase { public: int type() { return int(LOAD_SAMPLE); } - uint32_t size() { return sizeof(EventLoadSample); } + uint32_t size() { return sizeof(EventLooperLoad); } - AudioBuffer* audioBufferPtr; + int track; + int clip; + AudioBuffer* audioBuffer; - EventLoadSample(AudioBuffer* a) - { - audioBufferPtr = a; - } + EventLooperLoad(){} + EventLooperLoad(int t, int c, AudioBuffer* ab) : track(t), clip(c), audioBuffer(ab) {} }; class EventPlaySample : public EventBase diff --git a/src/eventhandlerdsp.cxx b/src/eventhandlerdsp.cxx index 9071851..58975f6 100644 --- a/src/eventhandlerdsp.cxx +++ b/src/eventhandlerdsp.cxx @@ -38,11 +38,12 @@ void handleDspEvents() jack_ringbuffer_read( rbToDsp, (char*)&ev, sizeof(EventMasterVol) ); //jack->masterVolume = ev.vol; } break; } - case Event::LOAD_SAMPLE: { - if ( availableRead >= sizeof(EventLoadSample) ) { - EventLoadSample ev(0); - jack_ringbuffer_read( rbToDsp, (char*)&ev, sizeof(EventLoadSample) ); - //jack->addAudioBuffer( ev.audioBufferPtr ); + case Event::LOOPER_LOAD: { + if ( availableRead >= sizeof(EventLooperLoad) ) { + EventLooperLoad ev; + jack_ringbuffer_read( rbToGui, (char*)&ev, sizeof(EventLooperLoad) ); + Looper* l = jack->getLooper( ev.track ); + } break; } case Event::PLAY_SAMPLE: { if ( availableRead >= sizeof(EventPlaySample) ) { diff --git a/src/eventhandlergui.cxx b/src/eventhandlergui.cxx index f149a4b..0b5e395 100644 --- a/src/eventhandlergui.cxx +++ b/src/eventhandlergui.cxx @@ -40,12 +40,6 @@ void handleGuiEvents() jack_ringbuffer_read( rbToGui, (char*)&ev, sizeof(EventMasterVol) ); //jack->masterVolume = ev.vol; } break; } - case Event::LOAD_SAMPLE: { - if ( availableRead >= sizeof(EventLoadSample) ) { - EventLoadSample ev(0); - jack_ringbuffer_read( rbToGui, (char*)&ev, sizeof(EventLoadSample) ); - //jack->addAudioBuffer( ev.audioBufferPtr ); - } break; } case Event::PLAY_SAMPLE: { if ( availableRead >= sizeof(EventPlaySample) ) { EventPlaySample ev(0,0); diff --git a/src/gtrack.hxx b/src/gtrack.hxx index ce5f8f4..bac61a8 100644 --- a/src/gtrack.hxx +++ b/src/gtrack.hxx @@ -8,16 +8,41 @@ #include #include #include +#include #include "avtk/avtk_dial.h" #include "avtk/avtk_button.h" #include "avtk/avtk_background.h" +#include "worker.hxx" +#include "audiobuffer.hxx" #include "eventhandler.hxx" using namespace std; +static string choose_file() +{ + string path; + Fl_Native_File_Chooser fnfc; + fnfc.title("Pick a file"); + fnfc.type(Fl_Native_File_Chooser::BROWSE_FILE); + //fnfc.filter("Wav\t*.wav"); + fnfc.directory( getenv("HOME") ); // 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()); + + // update path and load it + path = fnfc.filename(); + + break; // FILE CHOSEN + } + return path; +} + static void gtrack_button_callback(Fl_Widget *w, void *data) { int track = 0; if ( data ) @@ -49,6 +74,13 @@ static void gtrack_button_callback(Fl_Widget *w, void *data) { EventLooperLoopLength e = EventLooperLoopLength(track, 0.5); writeToDspRingbuffer( &e ); } + else if ( strcmp( w->label() , "Load" ) == 0 ) + { + AudioBuffer* ab = Worker::loadSample( choose_file() ); + + EventLooperLoad e = EventLooperLoad( track, 0 , ab ); + writeToDspRingbuffer( &e ); + } else if ( strcmp( w->label() , "Vol" ) == 0 ) { @@ -73,7 +105,7 @@ class GTrack : public Fl_Group button4(x + 5, y + 84, 48, 18,"-"), button5(x +57, y + 84, 48, 18,"+"), - button6(x + 5, y +104, 18, 18,"6"), + button6(x + 5, y +104, 100, 18,"Load"), volume(x+55-22, y +175, 34, 34, "Vol"), diff --git a/src/gui.cxx b/src/gui.cxx index 13b0d34..f38a8cb 100644 --- a/src/gui.cxx +++ b/src/gui.cxx @@ -4,9 +4,12 @@ #include +#include "audiobuffer.hxx" + // Hack, move to gtrack.cpp int GTrack::privateID = 0; int GMasterTrack::privateID = 0; +int AudioBuffer::privateID = 0; using namespace std; diff --git a/src/jack.hxx b/src/jack.hxx index b0282ff..3358727 100644 --- a/src/jack.hxx +++ b/src/jack.hxx @@ -43,6 +43,10 @@ class Jack { loopers.at(t)->setLoopLength(l); } + Looper* getLooper(int t) + { + return loopers.at(t); + } Metronome* getMetronome(){return &metronome;} TimeManager* getTimeManager(){return &timeManager;} diff --git a/src/looper.cxx b/src/looper.cxx index 6bdd9c9..606bd51 100644 --- a/src/looper.cxx +++ b/src/looper.cxx @@ -122,6 +122,17 @@ void Looper::updateControllers() } } +void Looper::setSample(int c, int nB, int bS, float* bP) +{ + if ( bS > SAMPLE_SIZE ) + { + EventGuiPrint e( "Looper setSample() size > incoming sample" ); + writeToGuiRingbuffer( &e ); + } + numBeats = nB; + memcpy( &sample[0], bP, bS ); // copy sample data to pre-allocated buffer +} + void Looper::process(int nframes, Buffers* buffers) { float* in = buffers->audio[Buffers::MASTER_INPUT]; diff --git a/src/looper.hxx b/src/looper.hxx index 05ea25c..6feae56 100644 --- a/src/looper.hxx +++ b/src/looper.hxx @@ -26,6 +26,8 @@ class Looper : public Observer // for notifications Looper(int t); + void setSample(int c, int nB, int bS, float* bP); + void midi(unsigned char* data); void bar(); diff --git a/src/worker.hxx b/src/worker.hxx new file mode 100644 index 0000000..e3dcb55 --- /dev/null +++ b/src/worker.hxx @@ -0,0 +1,36 @@ + +#ifndef LUPPP_WORKER_H +#define LUPPP_WORKER_H + +// Library +#include + +#include + +#include "audiobuffer.hxx" + +using namespace std; + +namespace Worker +{ + static AudioBuffer* loadSample( string path ) + { + SndfileHandle infile( path, SFM_READ ); + + + AudioBuffer* ab = new AudioBuffer(); + + std::vector buf( infile.frames(), 0.f ); + + infile.read( &buf[0] , infile.frames() ); + + // read data from file + ab->setBeats(4); + ab->nonRtSetSample( buf ); + + cout << "Worker: loadSample() " << path << " size: " << infile.frames() << endl; + return ab; + } +} + +#endif // LUPPP_WORKER_H diff --git a/wscript b/wscript index e7f286a..47bfc6a 100644 --- a/wscript +++ b/wscript @@ -15,7 +15,7 @@ def configure(conf): conf.check_cfg(package='ntk',at_least_version='1.3',args='--cflags --libs',uselib_store='NTK') conf.check_cfg(package='jack',at_least_version='0.118',args='--cflags --libs',uselib_store='JACK') #conf.check_cfg(package='lilv-0',at_least_version='1.0',args='--cflags --libs',uselib_store='LILV') - #conf.check_cfg(package='sndfile',at_least_version='1.0',args='--cflags --libs',uselib_store='SNDFILE') + conf.check_cfg(package='sndfile',at_least_version='1.0',args='--cflags --libs',uselib_store='SNDFILE') def build(bld): @@ -27,5 +27,5 @@ def build(bld): 'src/eventhandlergui.cxx', 'src/eventhandlerdsp.cxx'] - bld.program(source = sources, target='luppp5', use='JACK NTK') + bld.program(source = sources, target='luppp5', use='JACK NTK SNDFILE')