/* * Author: Harry van Haaren 2013 * harryhaaren@gmail.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "gmastertrack.hxx" #include #include static void gmastertrack_tempoDial_callback(Fl_Widget *w, void *data) { Avtk::Dial* b = (Avtk::Dial*)w; float bpm = (b->value() * (float)(MAX_TEMPO - MIN_TEMPO) + MIN_TEMPO); if(std::fabs(bpm-round(bpm))) { LOOPP_WARN("%f",bpm); } EventTimeBPM e = EventTimeBPM( bpm ); writeToDspRingbuffer( &e ); } static void gmastertrack_volume_callback(Fl_Widget *w, void *data) { Avtk::Volume* b = (Avtk::Volume*)w; float v = b->value(); EventMasterVol e( v ); writeToDspRingbuffer( &e ); } static void gmastertrack_inputVolume_callback(Fl_Widget *w, void *data) { Avtk::Volume* b = (Avtk::Volume*)w; float v = b->value(); EventMasterInputVol e( v ); writeToDspRingbuffer( &e ); } static void gmastertrack_sidchainKeyButton_callback(Fl_Widget *w, void *data) { Avtk::LightButton* b = (Avtk::LightButton*)w; b->value( !b->value() ); EventMasterInputToActive e( INPUT_TO_SIDE_KEY, b->value() ); writeToDspRingbuffer( &e ); //printf("Key button\n"); } static void gmastertrack_mixButton_callback(Fl_Widget *w, void *data) { Avtk::LightButton* b = (Avtk::LightButton*)w; b->value( !b->value() ); EventMasterInputToActive e( INPUT_TO_MIX, b->value() ); writeToDspRingbuffer( &e ); //printf("Mix button\n"); } static void gmastertrack_sendButton_callback(Fl_Widget *w, void *data) { Avtk::LightButton* b = (Avtk::LightButton*)w; b->value( !b->value() ); EventMasterInputToActive e( INPUT_TO_SEND, b->value() ); writeToDspRingbuffer( &e ); //printf("Send button\n"); } static void gmastertrack_sendVol_callback(Fl_Widget *w, void *data) { Avtk::Dial* b = (Avtk::Dial*)w; float v = b->value(); EventMasterInputTo e = EventMasterInputTo( INPUT_TO_SEND, v ); writeToDspRingbuffer( &e ); ///printf("Send dial\n"); } static void gmastertrack_xSideVol_callback(Fl_Widget *w, void *data) { Avtk::Dial* b = (Avtk::Dial*)w; float v = b->value(); EventMasterInputTo e = EventMasterInputTo( INPUT_TO_XSIDE, v ); writeToDspRingbuffer( &e ); //printf("XSide dial\n"); } /// return volume static void gmastertrack_returnVol_callback(Fl_Widget *w, void *data) { Avtk::Dial* b = (Avtk::Dial*)w; float v = b->value(); EventMasterReturn e( RETURN_MAIN, v ); writeToDspRingbuffer( &e ); //printf("Return dial\n"); } static void gmastertrack_mixVol_callback(Fl_Widget *w, void *data) { Avtk::Dial* b = (Avtk::Dial*)w; float v = b->value(); EventMasterInputTo e = EventMasterInputTo( INPUT_TO_MIX, v ); writeToDspRingbuffer( &e ); } static void gmastertrack_transport_callback(Fl_Widget *w, void *data) { Avtk::LightButton* b = (Avtk::LightButton*)w; if( b->value() ) { EventTransportState e = EventTransportState( TRANSPORT_ROLLING ); writeToDspRingbuffer( &e ); w->label( "Stop" ); b->value( 0 ); } else { EventTransportState e = EventTransportState( TRANSPORT_STOPPED ); writeToDspRingbuffer( &e ); w->label( "Play" ); b->value( 1 ); } } static void gmastertrack_button_callback(Fl_Widget *w, void *data) { if ( strcmp( w->label(), "Metro" ) == 0 ) { if ( Fl::event_button() == FL_RIGHT_MOUSE ) { // popup volume menu: 10 "steps of volume" Fl_Menu_Item rclick_menu[] = { { "Vol 100%" }, { "Vol 75%" }, { "Vol 50%" }, { "Vol 25%"}, { 0 } }; Fl_Menu_Item *m = (Fl_Menu_Item*) rclick_menu->popup( Fl::event_x(), Fl::event_y(), 0, 0, 0); float v = 0.f; if ( !m ) { return; } else if ( strcmp(m->label(), "Vol 100%") == 0 ) { v = 1; } else if ( strcmp(m->label(), "Vol 75%") == 0 ) { v = 0.75; } else if ( strcmp(m->label(), "Vol 50%") == 0 ) { v = 0.5; } else v = 0.25; LOOPP_NOTE("metro vol = %f", v ); EventMetronomeVolume e( v ); writeToDspRingbuffer( &e ); } else { Avtk::LightButton* b = (Avtk::LightButton*)w; EventMetronomeActive e = EventMetronomeActive( !b->value() ); writeToDspRingbuffer( &e ); } } else if ( strcmp( w->label(), "Tap" ) == 0 ) { if ( Fl::event_button() == FL_RIGHT_MOUSE ) { const char* answer = fl_input("Enter BPM value (range %d and %d):", 0, MIN_TEMPO, MAX_TEMPO); if(answer) { float bpm = atof(answer); if ( bpm >= MIN_TEMPO && bpm <= MAX_TEMPO) { EventTimeBPM e = EventTimeBPM( bpm ); writeToDspRingbuffer( &e ); } } } else { EventTimeTempoTap e; writeToDspRingbuffer( &e ); } } else { LOOPP_WARN("Error: unknown command string"); } } static void gmastertrack_autoStopRec_callback(Fl_Widget *w, void *data) { int clipLength = -1; if(Fl::event_button() == FL_LEFT_MOUSE) { Fl_Menu_Item rclick_menu[] = { { "1" }, { "2" }, { "4" }, { "8" }, { "16" }, { "∞" }, { "Custom" }, { 0 } }; Fl_Menu_Item *m = (Fl_Menu_Item *)rclick_menu->popup( Fl::event_x(), Fl::event_y(), 0, 0, 0); if(!m) { return; } else if(strcmp(m->label(), "Custom") == 0) { const char *answer = fl_input( // TODO magic number "Enter Clip Length (range 1 and 64):", 0); if(answer) { clipLength = atoi(answer); // TODO magic number if(clipLength < 1 || clipLength > 64) { // do not accept invalid input clipLength = -1; } } } else if(strcmp(m->label(), "∞") == 0) { clipLength = 0; } else { clipLength = atoi(m->label()); } } else { clipLength = 0; } if(clipLength >= 0) { EventAutoStopRecClipLength e = EventAutoStopRecClipLength(clipLength); writeToDspRingbuffer(&e); } } static void gmastertrack_freeRecMode_callback(Fl_Widget *w, void *data) { Avtk::LightButton *b = (Avtk::LightButton *)w; EventFreeRecordMode e = EventFreeRecordMode(!b->value()); writeToDspRingbuffer(&e); } #define HEIGHT 38 #define OFST 49 #define COLUMN_RIGHT x + w * 2 / 4.f - 15 #define COLUMN_LEFT x + w * 1 / 4.f - 26 #define ROW y + 436 GMasterTrack::GMasterTrack ( int x, int y, int w, int h, const char *l ) : Fl_Group ( x, y, w, h ), title ( strdup ( l ) ), bg ( x, y, w, h, title ), // with "true" master flag: launches scenes instead of clips on tracks clipSel ( x + 5, y + 26 + 102, 140, 294, "", true ), source ( x + 5, y + 26, 140, 100, "" ), volBox ( x + 5, y + 422, 140, 222, "" ), freeRec ( COLUMN_LEFT, ROW + OFST * 0, 40, HEIGHT, "Free" ), transport ( COLUMN_LEFT, ROW + OFST * 1, 40, HEIGHT, "Stop" ), tapTempo ( COLUMN_RIGHT, ROW + OFST * 2, 40, HEIGHT, "Tap" ), metronomeButton ( COLUMN_RIGHT, ROW + OFST * 1, 40, HEIGHT, "Metro" ), autoStopRecButton ( COLUMN_RIGHT, ROW + OFST * 0, 40, HEIGHT, "∞" ), beatLight ( COLUMN_LEFT, ROW + OFST * 2, 40, HEIGHT, "" ), tempoDial ( COLUMN_RIGHT, ROW + OFST * 3, 40, HEIGHT, "BPM" ), returnVol ( COLUMN_LEFT, ROW + OFST * 3, 40, HEIGHT, "Return" ), inputVolume ( x + 9, y + 26 + 4, w - 18, 30, "" ), inputToSend ( x + 10, y + 28 + 68, 40, 26, "Snd" ), inputToSendVol ( x + w * 0.2 - 15, y + 28 + 36, 30, 30, "" ), inputToSidechainKey ( x + w * 0.5 - 20, y + 28 + 68, 40, 26, "Key" ), inputToSidechainSignalVol ( x + w * 0.5 - 15, y + 28 + 36, 30, 30, "" ), 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, 216, "" ) { ID = privateID++; bar = 0; inputVolume.value(0.5); inputVolume.setOrientationHorizontal(); inputVolume.callback( gmastertrack_inputVolume_callback, 0 ); transport.callback( gmastertrack_transport_callback, &ID ); tapTempo.callback( gmastertrack_button_callback, &ID ); metronomeButton.callback( gmastertrack_button_callback, 0 ); autoStopRecButton.callback(gmastertrack_autoStopRec_callback, &ID); freeRec.callback(gmastertrack_freeRecMode_callback, &ID); freeRec.value(0); tempoDial.callback( gmastertrack_tempoDial_callback, 0 ); inputToSend.setColor( 0, 1.0, 0 ); inputToSend.callback( gmastertrack_sendButton_callback, 0 ); inputToSendVol.callback( gmastertrack_sendVol_callback, 0 ); inputToSidechainKey.setColor( 0, 0.6, 1 ); inputToSidechainKey.callback( gmastertrack_sidchainKeyButton_callback, 0 ); inputToSidechainSignalVol.value( 0 ); inputToSidechainSignalVol.callback( gmastertrack_xSideVol_callback, 0 ); inputToMix.callback ( gmastertrack_mixButton_callback, 0 ); inputToMixVol.callback ( gmastertrack_mixVol_callback, 0 ); tempoDial.align( FL_ALIGN_BOTTOM ); returnVol.value( 1.f ); returnVol.align( FL_ALIGN_BOTTOM ); returnVol.callback( gmastertrack_returnVol_callback, 0 ); beatLightEnable(true); volume.amplitude( 0.0, 0.0 ); volume.callback( gmastertrack_volume_callback, 0 ); end(); // close the group } void GMasterTrack::setBpm( float b ) { bpm = b; if(!tempoDial.mouseClicked) { tempoDial.value( (bpm - MIN_TEMPO) / (float)(MAX_TEMPO - MIN_TEMPO)); } std::stringstream s; s << round(bpm*10)/10; tempoDial.copy_label( s.str().c_str() ); tempoDial.redraw(); } void GMasterTrack::setInputVol(float f) { //LOOPP_NOTE(" gmtrck, inputVol %f", f ); inputVolume.value( f ); } void GMasterTrack::setReturnVol(float f) { LOOPP_NOTE(" gmtrck, returnVol %f", f ); returnVol.value( f ); } void GMasterTrack::setInputTo(int to, float f) { //LOOPP_NOTE(" gmtrck, inputTO %i, %f", to, f ); if ( to == Event::INPUT_TO_MIX ) inputToMixVol.value( f ); else if ( to == Event::INPUT_TO_SEND ) inputToSendVol.value( f ); else if ( to == Event::INPUT_TO_XSIDE ) inputToSidechainSignalVol.value( f ); } void GMasterTrack::setInputToActive(int to, bool f) { //LOOPP_NOTE(" gmtrck, inputToActive %i, %i", to, int(f) ); if ( to == Event::INPUT_TO_MIX ) inputToMix.value( f ); else if ( to == Event::INPUT_TO_SEND ) inputToSend.value( f ); else if ( to == Event::INPUT_TO_SIDE_KEY ) inputToSidechainKey.value( f ); } void GMasterTrack::metronomeEnable(bool b) { if(b) metronomeButton.activate(); else metronomeButton.deactivate(); } void GMasterTrack::metronomeActivate(bool b) { metronomeButton.value(b); } void GMasterTrack::tapEnable(bool b) { if(b) tapTempo.activate(); else tapTempo.deactivate(); } void GMasterTrack::beatLightEnable(bool b) { if(b) { beatLight.activate(); beatLight.value(1); } else { beatLight.deactivate(); beatLight.value(0); beatLight.copy_label(""); beatLight.redraw(); } } void GMasterTrack::tempoDialEnable(bool b) { if(b) tempoDial.activate(); else tempoDial.deactivate(); } void GMasterTrack::setClipLength(int l) { const char *str; if(l == 0) { str = "∞"; } else { std::string tmp = std::to_string(l); str = tmp.c_str(); } autoStopRecButton.copy_label(str); } void GMasterTrack::setFreeRecMode(bool e) { freeRec.value(e); } void GMasterTrack::enableFreeRecMode ( bool e ) { if ( e ) { freeRec.activate (); } else { freeRec.deactivate (); } } void GMasterTrack::enableTempoDial ( bool e ) { if(e) { tempoDial.activate (); } else { tempoDial.deactivate (); } } float GMasterTrack::getBpm() { return bpm; } void GMasterTrack::setTapTempo( bool b ) { tapTempo.setHighlight( b ); } void GMasterTrack::setBarBeat(int b, int beat) { if(beatLight.active()) { // FIXME hard coded beat number int beat_num = beat % 4; switch(beat_num) { case 0: beatLight.setColor(1.0, 0.0, 0.0); break; case 1: beatLight.setColor(1.0, 0.48, 0.0); break; case 2: beatLight.setColor(1.0, 1.0, 0.0); break; case 3: beatLight.setColor(0.0, 1.0, 0.0); break; default: break; } char buf[2]; sprintf(buf, "%d", beat_num + 1); beatLight.copy_label(buf); beatLight.redraw(); } } Avtk::Volume* GMasterTrack::getInputVolume() { return &inputVolume; } Avtk::Volume* GMasterTrack::getVolume() { return &volume; } Avtk::LightButton* GMasterTrack::getInputToSend() { return &inputToSend; } Avtk::LightButton* GMasterTrack::getInputToSidechainKey() { return &inputToSidechainKey; } Avtk::LightButton* GMasterTrack::getInputToMix() { return &inputToMix; } Avtk::Dial* GMasterTrack::getInputToSendVol() { return &inputToSendVol; } Avtk::Dial* GMasterTrack::getInputToXSide() { return &inputToSidechainSignalVol; } Avtk::Dial* GMasterTrack::getInputToMixVol() { return &inputToMixVol; } Avtk::ClipSelector* GMasterTrack::getClipSelector() { return &clipSel; } GMasterTrack::~GMasterTrack() { free(title); }