Mercurial > hg > opencollidoscope
changeset 1:b5bcad8e7803
renamed teensy files
added DeviceManageJack.cpp
author | Fiore Martin <f.martin@qmul.ac.uk> |
---|---|
date | Fri, 08 Jul 2016 11:39:18 +0200 |
parents | 02467299402e |
children | dd889fff8423 |
files | CollidoscopeTeensy/CollidoscopeTeensy_new.ino CollidoscopeTeensy/CollidoscopeTeensy_original.ino JackDevice/ContextJack.cpp JackDevice/ContextJack.h JackDevice/DeviceManagerJack.cpp JackDevice/DeviceManagerJack.h TeensyCode/collidoscope_double_knob.ino TeensyCode/collidoscope_single_knob.ino |
diffstat | 8 files changed, 1231 insertions(+), 1085 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CollidoscopeTeensy/CollidoscopeTeensy_new.ino Fri Jul 08 11:39:18 2016 +0200 @@ -0,0 +1,323 @@ + +/****************************************************************************** + + * Ben Bengler + * mail@benbengler.com + * 02.05.2016 + * + * Collidoscope + * + * Teensy 2 ++ pinout: https://www.pjrc.com/teensy/card4b.pdf + * + * ANALOG INPUTS: + * Wavejet -> F0 (38) [Horizontal rail 1] + * Wavejet -> F1 (39) [Horizontal rail 2] + * Filter 1 -> F2 (40) [Vertical rail 1] + * Filter 2 -> F4 (42) [Vertical rail 2] + * + * DIGITAL INPUTS [INTERRUPTS]: + * Sel. length 1 -> INT0/INT1 (0, 1) [Encoder 1] + * Sel. length 2 -> INT2/INT3 (2, 3) [Encoder 2] + * Duration 1 -> INT4/INT5 (36, 37)[Encoder 3] + * Duration 2 -> INT6/INT7 (18, 19)[Encoder 4] + * + * DIGITAL INPUTS: + * Play1 toggle -> B0 (20) + * Record1 -> B1 (21) + * Play2 toggle -> B3 (22) + * Record2 -> B4 (24) + * + * DIGITAL OUTPUTS: + * Record Button 1 Led -> D4 (4) + * Record Button 2 Led -> D5 (5) + + ******************************************************************************/ + + +#include <Encoder.h> +#include <Bounce.h> + +/////////////////////////////////////////////////// +//MIDI settings +const int midi_chan_inst1 = 1; // MIDI channel for Instrument 1 +const int midi_chan_inst2 = 2; // MIDI channel for Instrument 2 + +const int cc_length = 1; // MIDI cc controlling selection length +const int cc_duration = 2; // MIDI cc controlling duration +const int cc_filter = 7; // MIDI cc controlling LP filter +const int cc_play = 4; // MIDI cc controlling PLAY +const int cc_record = 5; // MIDI cc controlling RECORD +//const int cc_reset = 100; // MIDI cc controlling instrument RESET + +/////////////////////////////////////////////////// +//Default Values: +const int Enc_def = 64; //default selection length +int MIDI_led_state = LOW; +//boolean reset1 = true; +//boolean reset2 = true; + +/////////////////////////////////////////////////// +// Interface Inputs + +//Buttons: + +const int Pin_play1 = 20; //B0 +const int Pin_record1 = 21; //B1 +const int Pin_play2 = 23; //B3 +const int Pin_record2 = 24; //B4 +const int Pin_record1_led = 4; //D4 +const int Pin_record2_led = 5; //D5 +const int Pin_MIDIled = 6; + +//const int Pin_reset1 = 22; //B2, not in use +//const int Pin_reset2 = 25; //B5, not in use + +Bounce button1 = Bounce(Pin_play1, 5); +Bounce button2 = Bounce(Pin_record1, 5); +Bounce button3 = Bounce(Pin_play2, 5); +Bounce button4 = Bounce(Pin_record2, 5); + + +//Encoder +Encoder Enc1 (0, 1); //Encoder for section length on Wavejet 1 +Encoder Enc2 (2, 3); //Encoder for section length on Wavejet 2 +Encoder Enc3 (36, 37); //Encoder for duration of Wavejet 1 [granularisation effect] +Encoder Enc4 (18, 19); //Encoder for duration of Wavejet 2 [granularisation effect] + +// Variables +const int jitter_thresh = 10; //7threshold value for analog INs to suppress sending MIDI due to input jitter +const int jitter_thresh_short = 5; + +void setup() { + +pinMode(Pin_play1, INPUT_PULLUP); +pinMode(Pin_record1, INPUT_PULLUP); +pinMode(Pin_play2, INPUT_PULLUP); +pinMode(Pin_record2, INPUT_PULLUP); + + +pinMode(Pin_MIDIled, OUTPUT); +pinMode(Pin_record1_led, OUTPUT); +pinMode(Pin_record2_led, OUTPUT); +} + +//Store recent values to detect parameter change +long Enc1_old = -999; +long Enc2_old = -999; +long Enc3_old = -999; +long Enc4_old = -999; + +uint16_t Jet1_old = 0; +int16_t Jet1_old_MIDI = -1; +uint16_t Jet2_old = 0; +int16_t Jet2_old_MIDI = -1; +uint16_t filter1_old = 0; +int16_t filter1_old_MIDI = -1; +uint16_t filter2_old = 0; +int16_t filter2_old_MIDI = -1; + +void loop() { + + digitalWrite(Pin_MIDIled, LOW); + digitalWrite(Pin_record1_led, HIGH); + digitalWrite(Pin_record2_led, HIGH); + button1.update(); + button2.update(); + button3.update(); + button4.update(); + + + uint16_t Jet1_new = analogRead(0); //read Wavejet/Rail 1 + uint16_t Jet2_new = analogRead(1); //read Wavejet/Rail 2 + uint16_t filter1_new = analogRead(2); //read filter Instrument 1; ADJUST INPUT RANGE ACCORDING TO SENSOR + uint16_t filter2_new = analogRead(4); //read filter Instrument 2; ADJUST INPUT RANGE ACCORDING TO SENSOR + + + + //Encoder 1 [Controls selection length of wave 1] + long Enc1_new = Enc1.read(); + Enc1_new = constrain(Enc1_new, 0, 127); //constrain to 7-bit MIDI range + + //Dynamic reset of counter to MIDI range + if (Enc1_new <= 0){ + Enc1.write(0); + } + else if (Enc1_new >= 127){ + Enc1.write(127); + } + + //Encoder 2 [Controls selection length of wave 2] + long Enc2_new = Enc2.read(); + Enc2_new = constrain(Enc2_new, 0, 127); //constrain to 7-bit MIDI range + + //Dynamic reset of counter to MIDI range + if (Enc2_new <= 0){ + Enc2.write(0); + } + else if (Enc2_new >= 127){ + Enc2.write(127); + } + + //Encoder 3 [Controls duration of wave 1] + long Enc3_new = Enc3.read(); + Enc3_new = constrain(Enc3_new, 0, 127); //constrain to 7-bit MIDI range + + //Dynamic reset of counter to MIDI range + if (Enc3_new <= 0){ + Enc3.write(0); + } + else if (Enc3_new >= 127){ + Enc3.write(127); + } + + //Encoder 4 [Controls duration of wave 2] + long Enc4_new = Enc4.read(); + Enc4_new = constrain(Enc4_new, 0, 127); //constrain to 7-bit MIDI range + + //Dynamic reset of counter to MIDI range + if (Enc4_new <= 0){ + Enc4.write(0); + } + else if (Enc4_new >= 127){ + Enc4.write(127); + } + + + //Instrument 1 Controls////////////////////////////////////// + + //Loop/Keymode Switch Instrument 1 + + if (button1.risingEdge()) { + //Serial.println("Loop mode"); + usbMIDI.sendControlChange(cc_play, 1, midi_chan_inst1); + } + + if (button1.fallingEdge()) { + //Serial.println("Keyboardmode mode"); + usbMIDI.sendControlChange(cc_play, 0, midi_chan_inst1); + } + + + //Record Instrument 1 + if (button2.fallingEdge()) { + //Serial.println("RECORD! Instrument 1"); + usbMIDI.sendControlChange(cc_record, 1, midi_chan_inst1); + } + + //send MIDI Wavejet 1 [Position Instrument 1] + if (Jet1_new > Jet1_old+jitter_thresh || Jet1_new < Jet1_old-jitter_thresh) { + + int16_t midiVal = constrain( map(Jet1_new, 988, 121, 0, 149), 0, 149 ); + // int16_t midiVal = constrain( map( Jet1_new, 23, 928, 0, 149 ), 0, 149 ); old collidoscope + if( midiVal != Jet1_old_MIDI ){ + Jet1_old_MIDI = midiVal; + usbMIDI.sendPitchBend( midiVal, midi_chan_inst1 ); + } + + Jet1_old = Jet1_new; + digitalWrite(Pin_MIDIled, HIGH); + } + + + //send MIDI Filter 1 [Filter Instrument 1] + + if ( filter1_new > filter1_old+jitter_thresh_short || filter1_new < filter1_old-jitter_thresh_short ) { // maybe adding jitter threshold needed, see Jet1_new + + int16_t midiVal = constrain( map(filter1_new, 145, 756, 0, 127), 0, 127 ); + if( midiVal != filter1_old_MIDI){ + //Serial.println( midiVal ); + filter1_old_MIDI = midiVal; + usbMIDI.sendControlChange(cc_filter, midiVal, midi_chan_inst1); + } + + filter1_old = filter1_new; + digitalWrite(Pin_MIDIled, HIGH); + } + + //send MIDI Encoder 1 [Selection length Instrument 1] + if (Enc1_new != Enc1_old) { + Enc1_old = Enc1_new; + //Serial.println("Encoder 1: "); + //Serial.println(Enc1_new); + usbMIDI.sendControlChange(cc_length, Enc1_new, midi_chan_inst1); + digitalWrite(Pin_MIDIled, HIGH); + } + + //send MIDI Encoder 3 [Duration Instrument 1] + if (Enc3_new != Enc3_old) { + Enc3_old = Enc3_new; + //Serial.println("Encoder 3: "); + //Serial.println(Enc3_new); + usbMIDI.sendControlChange(cc_duration, Enc3_new, midi_chan_inst1); + digitalWrite(Pin_MIDIled, HIGH); + } + + + //Instrument 2 Controls////////////////////////////////////// + + //Loop/Keymode Switch Instrument 2 + + if (button3.risingEdge()) { + //Serial.println("Loop mode"); + usbMIDI.sendControlChange(cc_play, 1, midi_chan_inst2); + } + + if (button3.fallingEdge()) { + //Serial.println("Keyboardmode mode"); + usbMIDI.sendControlChange(cc_play, 0, midi_chan_inst2); + } + + //Record Instrument 2 + if (button4.fallingEdge()) { + //Serial.println("RECORD! Instrument 2"); + usbMIDI.sendControlChange(cc_record, 1, midi_chan_inst2); + } + + //send MIDI Wavejet 2 [Position Instrument 2] + + if (Jet2_new > Jet2_old+jitter_thresh || Jet2_new < Jet2_old-jitter_thresh) { + //Serial.println("RECORD! Instrument 2"); + int16_t midiVal = constrain( map( Jet2_new, 109, 992, 149, 0 ), 0, 149 ); + if( midiVal != Jet2_old_MIDI ){ + Jet2_old_MIDI = midiVal; + usbMIDI.sendPitchBend( midiVal, midi_chan_inst2 ); + } + + Jet2_old = Jet2_new; + digitalWrite(Pin_MIDIled, HIGH); + } + + //Serial.println(filter2_new); + if ( filter2_new > filter2_old+jitter_thresh_short || filter2_new < filter2_old-jitter_thresh_short ) { // maybe adding jitter threshold needed, see Jet1_new + int16_t midiVal = constrain( map(filter2_new, 132, 700, 0, 127), 0, 127 ); + if( midiVal != filter2_old_MIDI){ + //Serial.println( midiVal ); + filter2_old_MIDI = midiVal; + usbMIDI.sendControlChange(cc_filter, midiVal, midi_chan_inst2); + } + + filter2_old = filter2_new; + digitalWrite(Pin_MIDIled, HIGH); + } + + + //send MIDI Encoder 2 [Selection length Instrument 2] + if (Enc2_new != Enc2_old) { + Enc2_old = Enc2_new; + //Serial.println("Encoder 2: "); + //Serial.println(Enc2_new); + usbMIDI.sendControlChange(cc_length, Enc2_new, midi_chan_inst2); + digitalWrite(Pin_MIDIled, HIGH); + } + + //send MIDI Encoder 4 [Duration Instrument 2] + if (Enc4_new != Enc4_old) { + Enc4_old = Enc4_new; + //Serial.println("Encoder 4: "); + //Serial.println(Enc4_new); + usbMIDI.sendControlChange(cc_duration, Enc4_new, midi_chan_inst2); + digitalWrite(Pin_MIDIled, HIGH); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CollidoscopeTeensy/CollidoscopeTeensy_original.ino Fri Jul 08 11:39:18 2016 +0200 @@ -0,0 +1,310 @@ + +/****************************************************************************** + + * Ben Bengler + * mail@benbengler.com + * 02.05.2016 + * + * Collidoscope + * + * Teensy 2 ++ pinout: https://www.pjrc.com/teensy/card4b.pdf + * + * ANALOG INPUTS: + * Wavejet -> F0 (38) [Horizontal rail 1] + * Wavejet -> F1 (39) [Horizontal rail 2] + * Filter 1 -> F2 (40) [Vertical rail 1] + * Filter 2 -> F4 (42) [Vertical rail 2] + * + * DIGITAL INPUTS [INTERRUPTS]: + * Sel. length 1 -> INT0/INT1 (0, 1) [Encoder 1] + * Sel. length 2 -> INT2/INT3 (2, 3) [Encoder 2] + * Duration 1 -> INT4/INT5 (36, 37)[Encoder 3] + * Duration 2 -> INT6/INT7 (18, 19)[Encoder 4] + * + * DIGITAL INPUTS: + * Play1 toggle -> B0 (20) + * Record1 -> B1 (21) + * Play2 toggle -> B3 (22) + * Record2 -> B4 (24) + * + * DIGITAL OUTPUTS: + * Record Button 1 Led -> D4 (4) + * Record Button 2 Led -> D5 (5) + + ******************************************************************************/ + + +#include <Encoder.h> +#include <Bounce.h> + +/////////////////////////////////////////////////// +//MIDI settings +const int midi_chan_inst1 = 1; // MIDI channel for Instrument 1 +const int midi_chan_inst2 = 2; // MIDI channel for Instrument 2 + +const int cc_length = 1; // MIDI cc controlling selection length +const int cc_duration = 2; // MIDI cc controlling duration +const int cc_filter = 7; // MIDI cc controlling LP filter +const int cc_play = 4; // MIDI cc controlling PLAY +const int cc_record = 5; // MIDI cc controlling RECORD +//const int cc_reset = 100; // MIDI cc controlling instrument RESET + +/////////////////////////////////////////////////// +//Default Values: +const int Enc_def = 64; //default selection length +int MIDI_led_state = LOW; +//boolean reset1 = true; +//boolean reset2 = true; + +/////////////////////////////////////////////////// +// Interface Inputs + +//Buttons: + +const int Pin_play1 = 20; //B0 +const int Pin_record1 = 21; //B1 +const int Pin_play2 = 23; //B3 +const int Pin_record2 = 24; //B4 +const int Pin_record1_led = 4; //D4 +const int Pin_record2_led = 5; //D5 +const int Pin_MIDIled = 6; + +//const int Pin_reset1 = 22; //B2, not in use +//const int Pin_reset2 = 25; //B5, not in use + +Bounce button1 = Bounce(Pin_play1, 5); +Bounce button2 = Bounce(Pin_record1, 5); +Bounce button3 = Bounce(Pin_play2, 5); +Bounce button4 = Bounce(Pin_record2, 5); + + +//Encoder +Encoder Enc1 (0, 1); //Encoder for section length on Wavejet 1 +Encoder Enc2 (2, 3); //Encoder for section length on Wavejet 2 + + +// Variables +const int jitter_thresh = 10; //7threshold value for analog INs to suppress sending MIDI due to input jitter + +void setup() { + +pinMode(Pin_play1, INPUT_PULLUP); +pinMode(Pin_record1, INPUT_PULLUP); +pinMode(Pin_play2, INPUT_PULLUP); +pinMode(Pin_record2, INPUT_PULLUP); + + +pinMode(Pin_MIDIled, OUTPUT); +pinMode(Pin_record1_led, OUTPUT); +pinMode(Pin_record2_led, OUTPUT); +} + +//Store recent values to detect parameter change +long Enc1_old = -999; +long Enc2_old = -999; + +uint16_t Jet1_old = 0; +int16_t Jet1_old_MIDI = -1; +uint16_t Jet2_old = 0; +int16_t Jet2_old_MIDI = -1; + +uint16_t filter1_old = 0; +int16_t filter1_old_MIDI = -1; +uint16_t filter2_old = 0; +int16_t filter2_old_MIDI = -1; + +uint16_t dur1_old = 0; +int16_t dur1_old_MIDI = -1; +uint16_t dur2_old = 0; +int16_t dur2_old_MIDI = -1; + +void loop() { + + digitalWrite(Pin_MIDIled, LOW); + digitalWrite(Pin_record1_led, HIGH); + digitalWrite(Pin_record2_led, HIGH); + button1.update(); + button2.update(); + button3.update(); + button4.update(); + + + uint16_t Jet1_new = analogRead(0); //read Wavejet/Rail 1 + uint16_t Jet2_new = analogRead(1); //read Wavejet/Rail 2 + uint16_t filter1_new = analogRead(2); //read filter Instrument 1; ADJUST INPUT RANGE ACCORDING TO SENSOR + uint16_t filter2_new = analogRead(4); //read filter Instrument 2; ADJUST INPUT RANGE ACCORDING TO SENSOR + uint16_t dur1_new = analogRead(3); + uint16_t dur2_new = analogRead(5); + + + //Encoder 1 [Controls selection length of wave 1] + long Enc1_new = Enc1.read(); + Enc1_new = constrain(Enc1_new, 0, 127); //constrain to 7-bit MIDI range + + //Dynamic reset of counter to MIDI range + if (Enc1_new <= 0){ + Enc1.write(0); + } + else if (Enc1_new >= 127){ + Enc1.write(127); + } + + //Encoder 2 [Controls selection length of wave 2] + long Enc2_new = Enc2.read(); + Enc2_new = constrain(Enc2_new, 0, 127); //constrain to 7-bit MIDI range + + //Dynamic reset of counter to MIDI range + if (Enc2_new <= 0){ + Enc2.write(0); + } + else if (Enc2_new >= 127){ + Enc2.write(127); + } + + //Instrument 1 Controls////////////////////////////////////// + + //Loop/Keymode Switch Instrument 1 + + if (button1.risingEdge()) { + //Serial.println("Loop mode"); + usbMIDI.sendControlChange(cc_play, 1, midi_chan_inst1); + } + + if (button1.fallingEdge()) { + //Serial.println("Keyboardmode mode"); + usbMIDI.sendControlChange(cc_play, 0, midi_chan_inst1); + } + + + //Record Instrument 1 + if (button2.fallingEdge()) { + //Serial.println("RECORD! Instrument 1"); + usbMIDI.sendControlChange(cc_record, 1, midi_chan_inst1); + } + + //send MIDI Wavejet 1 [Position Instrument 1] + + if (Jet1_new > Jet1_old+jitter_thresh || Jet1_new < Jet1_old-jitter_thresh) { + + int16_t midiVal = constrain( map(Jet1_new, 24, 926, 0, 149), 0, 149 ); + // int16_t midiVal = constrain( map( Jet1_new, 23, 928, 0, 149 ), 0, 149 ); old collidoscope + if( midiVal != Jet1_old_MIDI ){ + Jet1_old_MIDI = midiVal; + usbMIDI.sendPitchBend( midiVal, midi_chan_inst1 ); + } + + Jet1_old = Jet1_new; + digitalWrite(Pin_MIDIled, HIGH); + } + + + //send MIDI Filter 1 [Filter Instrument 1] + + if ( filter1_new != filter1_old ) { // maybe adding jitter threshold needed, see Jet1_new + + int16_t midiVal = constrain( map(filter1_new, 0, 1024, 0, 127), 0, 127 ); + if( midiVal != filter1_old_MIDI){ + //Serial.println( midiVal ); + filter1_old_MIDI = midiVal; + usbMIDI.sendControlChange(cc_filter, midiVal, midi_chan_inst1); + } + + filter1_old = filter1_new; + digitalWrite(Pin_MIDIled, HIGH); + } + + if ( dur1_new != dur1_old ) { // maybe adding jitter threshold needed, see Jet1_new + + int16_t midiVal = constrain( map(dur1_new, 0, 1024, 0, 127), 0, 127 ); + if( midiVal != dur1_old_MIDI){ + //Serial.println( midiVal ); + dur1_old_MIDI = midiVal; + usbMIDI.sendControlChange(cc_duration, midiVal, midi_chan_inst1); + } + + dur1_old = dur1_new; + digitalWrite(Pin_MIDIled, HIGH); + } + + //send MIDI Encoder 1 [Selection length Instrument 1] + if (Enc1_new != Enc1_old) { + Enc1_old = Enc1_new; + //Serial.println("Encoder 1: "); + //Serial.println(Enc1_new); + usbMIDI.sendControlChange(cc_length, Enc1_new, midi_chan_inst1); + digitalWrite(Pin_MIDIled, HIGH); + } + + + + //Instrument 2 Controls////////////////////////////////////// + + //Loop/Keymode Switch Instrument 2 + + if (button3.risingEdge()) { + //Serial.println("Loop mode"); + usbMIDI.sendControlChange(cc_play, 1, midi_chan_inst2); + } + + if (button3.fallingEdge()) { + //Serial.println("Keyboardmode mode"); + usbMIDI.sendControlChange(cc_play, 0, midi_chan_inst2); + } + + //Record Instrument 2 + if (button4.fallingEdge()) { + //Serial.println("RECORD! Instrument 2"); + usbMIDI.sendControlChange(cc_record, 1, midi_chan_inst2); + } + + //send MIDI Wavejet 2 [Position Instrument 2] + + if (Jet2_new > Jet2_old+jitter_thresh || Jet2_new < Jet2_old-jitter_thresh) { + //Serial.println("RECORD! Instrument 2"); + int16_t midiVal = constrain( map( Jet2_new, 925, 18, 149, 0 ), 0, 149 ); + if( midiVal != Jet2_old_MIDI ){ + Jet2_old_MIDI = midiVal; + usbMIDI.sendPitchBend( midiVal, midi_chan_inst2 ); + } + + Jet2_old = Jet2_new; + digitalWrite(Pin_MIDIled, HIGH); + } + + //Serial.println(filter2_new); + if ( filter2_new != filter2_old ) { // maybe adding jitter threshold needed, see Jet1_new + int16_t midiVal = constrain( map(filter2_new, 0, 1024, 0, 127), 0, 127 ); + if( midiVal != filter2_old_MIDI){ + //Serial.println( midiVal ); + filter2_old_MIDI = midiVal; + usbMIDI.sendControlChange(cc_filter, midiVal, midi_chan_inst2); + } + + filter2_old = filter2_new; + digitalWrite(Pin_MIDIled, HIGH); + } + + if ( dur2_new != dur2_old ) { // maybe adding jitter threshold needed, see Jet1_new + int16_t midiVal = constrain( map(dur2_new, 0, 1024, 0, 127), 0, 127 ); + if( midiVal != dur2_old_MIDI){ + //Serial.println( midiVal ); + dur2_old_MIDI = midiVal; + usbMIDI.sendControlChange(cc_duration, midiVal, midi_chan_inst2); + } + + dur2_old = dur2_new; + digitalWrite(Pin_MIDIled, HIGH); + } + + + //send MIDI Encoder 2 [Selection length Instrument 2] + if (Enc2_new != Enc2_old) { + Enc2_old = Enc2_new; + //Serial.println("Encoder 2: "); + //Serial.println(Enc2_new); + usbMIDI.sendControlChange(cc_length, Enc2_new, midi_chan_inst2); + digitalWrite(Pin_MIDIled, HIGH); + } + +} +
--- a/JackDevice/ContextJack.cpp Thu Jun 30 14:50:06 2016 +0200 +++ b/JackDevice/ContextJack.cpp Fri Jul 08 11:39:18 2016 +0200 @@ -1,301 +1,301 @@ -/* - Copyright (c) 2015, The Cinder Project - - This code is intended to be used with the Cinder C++ library, http://libcinder.org - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that - the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and - the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and - the following disclaimer in the documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "cinder/audio/linux/ContextJack.h" -#include "cinder/audio/Exception.h" - -namespace cinder { namespace audio { namespace linux { - -inline void zeroJackPort( jack_port_t *port, jack_nframes_t nframes ) -{ - // memset(port, 0, sizeof(jack_default_audio_sample_t) * nframes); -} - -inline void copyToJackPort(jack_port_t *port, float *source, jack_nframes_t nframes ) -{ - // dest, source, n - jack_default_audio_sample_t *out; - out = (jack_default_audio_sample_t *) jack_port_get_buffer( port, nframes ); - - memcpy( out, source, sizeof(jack_default_audio_sample_t) * nframes ) ; -} - -inline void copyFromJackPort(jack_port_t *port, float *dest, jack_nframes_t nframes ) -{ - // dest, source, n - jack_default_audio_sample_t *in; - in = (jack_default_audio_sample_t *) jack_port_get_buffer( port, nframes ); - - memcpy( dest, in, sizeof(jack_default_audio_sample_t) * nframes ) ; -} - - -int OutputDeviceNodeJack::jackCallback(jack_nframes_t nframes, void* userData) -{ - RenderData *renderData = static_cast<RenderData *>( userData ); - - OutputDeviceNodeJack *outputDeviceNode = static_cast<OutputDeviceNodeJack *>( renderData->outputNode ); - - auto ctx = renderData->outputNode->getContext(); - if( ! ctx ) { - for( size_t chan = 0; chan < 2; chan++) - // FIXME segfault at shutdown - zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes ); - - return 0; - } - - std::lock_guard<std::mutex> lock( ctx->getMutex() ); - - // verify associated context still exists, which may not be true if we blocked in ~Context() and were then deallocated. - ctx = renderData->outputNode->getContext(); - if( ! ctx ) { - - for( size_t chan = 0; chan < 2; chan++) - zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes ); - - return 0; - } - - - Buffer *internalBuffer = outputDeviceNode->getInternalBuffer(); - internalBuffer->zero(); - - ctx->preProcess(); - outputDeviceNode->pullInputs( internalBuffer ); - - // if clip detection is enabled and buffer clipped, silence it - if( false && outputDeviceNode->checkNotClipping() ){ - for( size_t chan = 0; chan < 2; chan++) - zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes ); - } - else { - for( size_t chan = 0; chan < 2; chan++) - copyToJackPort( outputDeviceNode->mOutputPorts[chan], internalBuffer->getChannel( chan ), nframes ); - } - - ctx->postProcess(); - - return 0; -} - -inline void OutputDeviceNodeJack::setInput( InputDeviceNodeRef inputDeviceNode) -{ - mInputDeviceNode = std::static_pointer_cast<InputDeviceNodeJack>(inputDeviceNode); -} - -ContextJack::ContextJack() -{ - -} - -ContextJack::~ContextJack() -{ - -} - - -OutputDeviceNodeRef ContextJack::createOutputDeviceNode( const DeviceRef &device, const Node::Format &format ) -{ - - if( mOutputDeviceNode == nullptr ) { - auto thisRef = std::static_pointer_cast<ContextJack>( shared_from_this() ); - - mOutputDeviceNode = makeNode( new OutputDeviceNodeJack( device, Node::Format().channels(2), thisRef ) ) ; - - if( mInputDeviceNode != nullptr){ - auto castedOutputDeviceNode = std::static_pointer_cast<OutputDeviceNodeJack>( mOutputDeviceNode ); - castedOutputDeviceNode->setInput( mInputDeviceNode ); - } - } - - return mOutputDeviceNode; -} - -InputDeviceNodeRef ContextJack::createInputDeviceNode( const DeviceRef &device, const Node::Format &format ) -{ - if( mInputDeviceNode == nullptr ) { - auto thisRef = std::static_pointer_cast<ContextJack>( shared_from_this() ); - - mInputDeviceNode = makeNode( new InputDeviceNodeJack( device, Node::Format().channels(2), thisRef ) ) ; - - if( mOutputDeviceNode != nullptr){ - auto castedOutputDeviceNode = std::static_pointer_cast<OutputDeviceNodeJack>( mOutputDeviceNode ); - castedOutputDeviceNode->setInput( mInputDeviceNode ); - } - } - - return mInputDeviceNode; -} - - -// OutputDeviceNodeJack - -OutputDeviceNodeJack::OutputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context ): - OutputDeviceNode( device, format), - mCinderContext( context ) -{ -} - -void OutputDeviceNodeJack::initialize() -{ - - const char *client_name = "Collidoscope"; - const char *server_name = NULL; - jack_options_t options = JackNullOption; - jack_status_t status; - - // connect to JAck server - mClient = jack_client_open (client_name, options, &status, server_name); - if( mClient == NULL){ - - std::string msg = "jack_client_open() failed. "; - if(status & JackServerFailed) - msg += "Unable to connect to Jack server"; - - throw cinder::audio::AudioContextExc(msg); - } - - - mRenderData.outputNode = this; - mRenderData.inputNode = mInputDeviceNode.get(); - CI_ASSERT(mInputDeviceNode != nullptr); - mRenderData.context = static_cast<ContextJack *>( getContext().get() ); - - // install callback - jack_set_process_callback (mClient, jackCallback, &mRenderData ); - - // jack shutdown ? - - - // setup output ports - mOutputPorts[0] = jack_port_register (mClient, "output1", - JACK_DEFAULT_AUDIO_TYPE, - JackPortIsOutput, 0); - - mOutputPorts[1] = jack_port_register (mClient, "output2", - JACK_DEFAULT_AUDIO_TYPE, - JackPortIsOutput, 0); - - if ((mOutputPorts[0] == NULL) || (mOutputPorts[0] == NULL)) { - throw cinder::audio::AudioContextExc("no more JACK ports available"); - } - - // setup input ports - mInputDeviceNode->mInputPorts[0] = jack_port_register (mClient, "input1", - JACK_DEFAULT_AUDIO_TYPE, - JackPortIsInput, 0); - - mInputDeviceNode->mInputPorts[1] = jack_port_register (mClient, "input2", - JACK_DEFAULT_AUDIO_TYPE, - JackPortIsInput, 0); - - - /* Tell the JACK server that we are ready to roll. Our callback will start running now. */ - if (jack_activate (mClient)) { - throw cinder::audio::AudioContextExc("cannot activate client"); - } - - // connect input ports to physical device (microphones) - const char **mikePorts = jack_get_ports (mClient, NULL, NULL, - JackPortIsPhysical|JackPortIsOutput); - - if (mikePorts == NULL) { - throw cinder::audio::AudioContextExc("no physical input ports available"); - } - - if (jack_connect (mClient, mikePorts[0], jack_port_name (mInputDeviceNode->mInputPorts[0]))) { - throw cinder::audio::AudioContextExc("cannot connect input port 0"); - } - - if (jack_connect (mClient, mikePorts[1], jack_port_name( mInputDeviceNode->mInputPorts[1]) )) { - throw cinder::audio::AudioContextExc("cannot connect input port 1"); - } - - // connect output ports to physical device (audio out ) - const char **speakerPorts = jack_get_ports (mClient, NULL, NULL, - JackPortIsPhysical|JackPortIsInput); - - if (speakerPorts == NULL) { - throw cinder::audio::AudioContextExc("no physical output ports available"); - } - - if (jack_connect (mClient, jack_port_name (mOutputPorts[0]), speakerPorts[0])) { - throw cinder::audio::AudioContextExc("cannot connect output port 0"); - } - - if (jack_connect (mClient, jack_port_name (mOutputPorts[1]), speakerPorts[1])) { - throw cinder::audio::AudioContextExc("cannot connect output port 1"); - } - - jack_free( mikePorts ); - jack_free( speakerPorts ); -} - - -void OutputDeviceNodeJack::uninitialize() -{ - jack_client_close( mClient ); -} - -void OutputDeviceNodeJack::enableProcessing() -{ -} - -void OutputDeviceNodeJack::disableProcessing() -{ -} - - -//-------------------------- InputDeviceNodeJack ------------------------------- - - -InputDeviceNodeJack::InputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context ): - InputDeviceNode( device, format) -{ -} - -void InputDeviceNodeJack::initialize() -{ -} - -void InputDeviceNodeJack::uninitialize() -{ -} - -void InputDeviceNodeJack::enableProcessing() -{ -} - -void InputDeviceNodeJack::disableProcessing() -{ -} - -void InputDeviceNodeJack::process( Buffer *buffer ) -{ - for( size_t chan = 0; chan < 2; chan++){ - copyFromJackPort(mInputPorts[chan], buffer->getChannel( chan ), buffer->getNumFrames() ); - } -} - -} } } // namespace cinder::audio::linux +/* + Copyright (c) 2015, The Cinder Project + + This code is intended to be used with the Cinder C++ library, http://libcinder.org + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that + the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and + the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + the following disclaimer in the documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "cinder/audio/linux/ContextJack.h" +#include "cinder/audio/Exception.h" + +namespace cinder { namespace audio { namespace linux { + +inline void zeroJackPort( jack_port_t *port, jack_nframes_t nframes ) +{ + // memset(port, 0, sizeof(jack_default_audio_sample_t) * nframes); +} + +inline void copyToJackPort(jack_port_t *port, float *source, jack_nframes_t nframes ) +{ + // dest, source, n + jack_default_audio_sample_t *out; + out = (jack_default_audio_sample_t *) jack_port_get_buffer( port, nframes ); + + memcpy( out, source, sizeof(jack_default_audio_sample_t) * nframes ) ; +} + +inline void copyFromJackPort(jack_port_t *port, float *dest, jack_nframes_t nframes ) +{ + // dest, source, n + jack_default_audio_sample_t *in; + in = (jack_default_audio_sample_t *) jack_port_get_buffer( port, nframes ); + + memcpy( dest, in, sizeof(jack_default_audio_sample_t) * nframes ) ; +} + + +int OutputDeviceNodeJack::jackCallback(jack_nframes_t nframes, void* userData) +{ + RenderData *renderData = static_cast<RenderData *>( userData ); + + OutputDeviceNodeJack *outputDeviceNode = static_cast<OutputDeviceNodeJack *>( renderData->outputNode ); + + auto ctx = renderData->outputNode->getContext(); + if( ! ctx ) { + for( size_t chan = 0; chan < 2; chan++) + // FIXME segfault at shutdown + zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes ); + + return 0; + } + + std::lock_guard<std::mutex> lock( ctx->getMutex() ); + + // verify associated context still exists, which may not be true if we blocked in ~Context() and were then deallocated. + ctx = renderData->outputNode->getContext(); + if( ! ctx ) { + + for( size_t chan = 0; chan < 2; chan++) + zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes ); + + return 0; + } + + + Buffer *internalBuffer = outputDeviceNode->getInternalBuffer(); + internalBuffer->zero(); + + ctx->preProcess(); + outputDeviceNode->pullInputs( internalBuffer ); + + // if clip detection is enabled and buffer clipped, silence it + if( false && outputDeviceNode->checkNotClipping() ){ + for( size_t chan = 0; chan < 2; chan++) + zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes ); + } + else { + for( size_t chan = 0; chan < 2; chan++) + copyToJackPort( outputDeviceNode->mOutputPorts[chan], internalBuffer->getChannel( chan ), nframes ); + } + + ctx->postProcess(); + + return 0; +} + +inline void OutputDeviceNodeJack::setInput( InputDeviceNodeRef inputDeviceNode) +{ + mInputDeviceNode = std::static_pointer_cast<InputDeviceNodeJack>(inputDeviceNode); +} + +ContextJack::ContextJack() +{ + +} + +ContextJack::~ContextJack() +{ + +} + + +OutputDeviceNodeRef ContextJack::createOutputDeviceNode( const DeviceRef &device, const Node::Format &format ) +{ + + if( mOutputDeviceNode == nullptr ) { + auto thisRef = std::static_pointer_cast<ContextJack>( shared_from_this() ); + + mOutputDeviceNode = makeNode( new OutputDeviceNodeJack( device, Node::Format().channels(2), thisRef ) ) ; + + if( mInputDeviceNode != nullptr){ + auto castedOutputDeviceNode = std::static_pointer_cast<OutputDeviceNodeJack>( mOutputDeviceNode ); + castedOutputDeviceNode->setInput( mInputDeviceNode ); + } + } + + return mOutputDeviceNode; +} + +InputDeviceNodeRef ContextJack::createInputDeviceNode( const DeviceRef &device, const Node::Format &format ) +{ + if( mInputDeviceNode == nullptr ) { + auto thisRef = std::static_pointer_cast<ContextJack>( shared_from_this() ); + + mInputDeviceNode = makeNode( new InputDeviceNodeJack( device, Node::Format().channels(2), thisRef ) ) ; + + if( mOutputDeviceNode != nullptr){ + auto castedOutputDeviceNode = std::static_pointer_cast<OutputDeviceNodeJack>( mOutputDeviceNode ); + castedOutputDeviceNode->setInput( mInputDeviceNode ); + } + } + + return mInputDeviceNode; +} + + +// OutputDeviceNodeJack + +OutputDeviceNodeJack::OutputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context ): + OutputDeviceNode( device, format), + mCinderContext( context ) +{ +} + +void OutputDeviceNodeJack::initialize() +{ + + const char *client_name = "Collidoscope"; + const char *server_name = NULL; + jack_options_t options = JackNullOption; + jack_status_t status; + + // connect to JAck server + mClient = jack_client_open (client_name, options, &status, server_name); + if( mClient == NULL){ + + std::string msg = "jack_client_open() failed. "; + if(status & JackServerFailed) + msg += "Unable to connect to Jack server"; + + throw cinder::audio::AudioContextExc(msg); + } + + + mRenderData.outputNode = this; + mRenderData.inputNode = mInputDeviceNode.get(); + CI_ASSERT(mInputDeviceNode != nullptr); + mRenderData.context = static_cast<ContextJack *>( getContext().get() ); + + // install callback + jack_set_process_callback (mClient, jackCallback, &mRenderData ); + + // jack shutdown ? + + + // setup output ports + mOutputPorts[0] = jack_port_register (mClient, "output1", + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput, 0); + + mOutputPorts[1] = jack_port_register (mClient, "output2", + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput, 0); + + if ((mOutputPorts[0] == NULL) || (mOutputPorts[0] == NULL)) { + throw cinder::audio::AudioContextExc("no more JACK ports available"); + } + + // setup input ports + mInputDeviceNode->mInputPorts[0] = jack_port_register (mClient, "input1", + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsInput, 0); + + mInputDeviceNode->mInputPorts[1] = jack_port_register (mClient, "input2", + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsInput, 0); + + + /* Tell the JACK server that we are ready to roll. Our callback will start running now. */ + if (jack_activate (mClient)) { + throw cinder::audio::AudioContextExc("cannot activate client"); + } + + // connect input ports to physical device (microphones) + const char **mikePorts = jack_get_ports (mClient, NULL, NULL, + JackPortIsPhysical|JackPortIsOutput); + + if (mikePorts == NULL) { + throw cinder::audio::AudioContextExc("no physical input ports available"); + } + + if (jack_connect (mClient, mikePorts[0], jack_port_name (mInputDeviceNode->mInputPorts[0]))) { + throw cinder::audio::AudioContextExc("cannot connect input port 0"); + } + + if (jack_connect (mClient, mikePorts[1], jack_port_name( mInputDeviceNode->mInputPorts[1]) )) { + throw cinder::audio::AudioContextExc("cannot connect input port 1"); + } + + // connect output ports to physical device (audio out ) + const char **speakerPorts = jack_get_ports (mClient, NULL, NULL, + JackPortIsPhysical|JackPortIsInput); + + if (speakerPorts == NULL) { + throw cinder::audio::AudioContextExc("no physical output ports available"); + } + + if (jack_connect (mClient, jack_port_name (mOutputPorts[0]), speakerPorts[0])) { + throw cinder::audio::AudioContextExc("cannot connect output port 0"); + } + + if (jack_connect (mClient, jack_port_name (mOutputPorts[1]), speakerPorts[1])) { + throw cinder::audio::AudioContextExc("cannot connect output port 1"); + } + + jack_free( mikePorts ); + jack_free( speakerPorts ); +} + + +void OutputDeviceNodeJack::uninitialize() +{ + jack_client_close( mClient ); +} + +void OutputDeviceNodeJack::enableProcessing() +{ +} + +void OutputDeviceNodeJack::disableProcessing() +{ +} + + +//-------------------------- InputDeviceNodeJack ------------------------------- + + +InputDeviceNodeJack::InputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context ): + InputDeviceNode( device, format) +{ +} + +void InputDeviceNodeJack::initialize() +{ +} + +void InputDeviceNodeJack::uninitialize() +{ +} + +void InputDeviceNodeJack::enableProcessing() +{ +} + +void InputDeviceNodeJack::disableProcessing() +{ +} + +void InputDeviceNodeJack::process( Buffer *buffer ) +{ + for( size_t chan = 0; chan < 2; chan++){ + copyFromJackPort(mInputPorts[chan], buffer->getChannel( chan ), buffer->getNumFrames() ); + } +} + +} } } // namespace cinder::audio::linux
--- a/JackDevice/ContextJack.h Thu Jun 30 14:50:06 2016 +0200 +++ b/JackDevice/ContextJack.h Fri Jul 08 11:39:18 2016 +0200 @@ -1,103 +1,103 @@ -/* - Copyright (c) 2015, The Cinder Project - - This code is intended to be used with the Cinder C++ library, http://libcinder.org - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that - the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and - the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and - the following disclaimer in the documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#pragma once - -#include "cinder/audio/Context.h" -#include <jack/jack.h> - -namespace cinder { namespace audio { namespace linux { - -class ContextJack; -class InputDeviceNodeJack; - -class OutputDeviceNodeJack : public OutputDeviceNode { - public: - OutputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context ); - - void setInput(InputDeviceNodeRef inputDeviceNode); - - protected: - void initialize() override; - void uninitialize() override; - void enableProcessing() override; - void disableProcessing() override; - bool supportsProcessInPlace() const override { return false; } - - private: - static int jackCallback(jack_nframes_t nframes, void* userData); - - - void renderToBufferFromInputs(); - - struct RenderData{ - RenderData() : inputNode(nullptr), outputNode(nullptr), context(nullptr){} - ~RenderData() { inputNode = nullptr; outputNode = nullptr; context = nullptr; } - Node* outputNode; - Node* inputNode; - ContextJack* context; - } mRenderData; - - std::weak_ptr<ContextJack> mCinderContext; - - jack_client_t *mClient; - - std::array< jack_port_t*, 2 > mOutputPorts; - - std::shared_ptr<InputDeviceNodeJack> mInputDeviceNode; -}; - -class InputDeviceNodeJack : public InputDeviceNode { - friend OutputDeviceNodeJack; - - public: - InputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context ); - - protected: - void initialize() override; - void uninitialize() override; - void enableProcessing() override; - void disableProcessing() override; - void process( Buffer *buffer ) override; - - private: - std::array< jack_port_t*, 2 > mInputPorts; -}; - -class ContextJack : public Context { - public: - ContextJack(); - virtual ~ContextJack(); - - - OutputDeviceNodeRef createOutputDeviceNode( const DeviceRef &device, const Node::Format &format = Node::Format() ) override; - InputDeviceNodeRef createInputDeviceNode( const DeviceRef &device, const Node::Format &format = Node::Format() ) override; - - OutputDeviceNodeRef mOutputDeviceNode; - InputDeviceNodeRef mInputDeviceNode; - - - private: -}; - -} } } // namespace cinder::audio::linux +/* + Copyright (c) 2015, The Cinder Project + + This code is intended to be used with the Cinder C++ library, http://libcinder.org + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that + the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and + the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + the following disclaimer in the documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once + +#include "cinder/audio/Context.h" +#include <jack/jack.h> + +namespace cinder { namespace audio { namespace linux { + +class ContextJack; +class InputDeviceNodeJack; + +class OutputDeviceNodeJack : public OutputDeviceNode { + public: + OutputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context ); + + void setInput(InputDeviceNodeRef inputDeviceNode); + + protected: + void initialize() override; + void uninitialize() override; + void enableProcessing() override; + void disableProcessing() override; + bool supportsProcessInPlace() const override { return false; } + + private: + static int jackCallback(jack_nframes_t nframes, void* userData); + + + void renderToBufferFromInputs(); + + struct RenderData{ + RenderData() : inputNode(nullptr), outputNode(nullptr), context(nullptr){} + ~RenderData() { inputNode = nullptr; outputNode = nullptr; context = nullptr; } + Node* outputNode; + Node* inputNode; + ContextJack* context; + } mRenderData; + + std::weak_ptr<ContextJack> mCinderContext; + + jack_client_t *mClient; + + std::array< jack_port_t*, 2 > mOutputPorts; + + std::shared_ptr<InputDeviceNodeJack> mInputDeviceNode; +}; + +class InputDeviceNodeJack : public InputDeviceNode { + friend OutputDeviceNodeJack; + + public: + InputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context ); + + protected: + void initialize() override; + void uninitialize() override; + void enableProcessing() override; + void disableProcessing() override; + void process( Buffer *buffer ) override; + + private: + std::array< jack_port_t*, 2 > mInputPorts; +}; + +class ContextJack : public Context { + public: + ContextJack(); + virtual ~ContextJack(); + + + OutputDeviceNodeRef createOutputDeviceNode( const DeviceRef &device, const Node::Format &format = Node::Format() ) override; + InputDeviceNodeRef createInputDeviceNode( const DeviceRef &device, const Node::Format &format = Node::Format() ) override; + + OutputDeviceNodeRef mOutputDeviceNode; + InputDeviceNodeRef mInputDeviceNode; + + + private: +}; + +} } } // namespace cinder::audio::linux
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/JackDevice/DeviceManagerJack.cpp Fri Jul 08 11:39:18 2016 +0200 @@ -0,0 +1,133 @@ +/* + Copyright (c) 2015, The Cinder Project + + This code is intended to be used with the Cinder C++ library, http://libcinder.org + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that + the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and + + the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + the following disclaimer in the documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "cinder/audio/linux/DeviceManagerJack.h" +#include "cinder/audio/Exception.h" +#include <jack/jack.h> + + +namespace cinder { namespace audio { namespace linux { + +DeviceManagerJack::DeviceManagerJack() +{ + + mDevices.push_back( addDevice("JackIn") ); + mDevices.push_back( addDevice("JackOut") ); + + jack_status_t status; + + jack_client_t *client = jack_client_open ("device info", JackNullOption, &status, NULL); + if( client == NULL){ + + std::string msg = "jack_client_open() failed. "; + if(status & JackServerFailed) + msg += "Unable to connect to Jack server"; + + throw cinder::audio::AudioContextExc(msg); + } + + mSampleRate = jack_get_sample_rate( client ); + mBufferSize = jack_get_buffer_size( client ); + + jack_client_close( client ); +} + +DeviceManagerJack::~DeviceManagerJack() +{ + +} + +const std::vector<DeviceRef>& DeviceManagerJack::getDevices() +{ + return mDevices; +} + +DeviceRef DeviceManagerJack::getDefaultOutput() +{ + return mDevices[1]; +} + +DeviceRef DeviceManagerJack::getDefaultInput() +{ + return mDevices[0]; +} + +std::string DeviceManagerJack::getName( const DeviceRef &device ) +{ + return device->getKey(); +} + +size_t DeviceManagerJack::getNumInputChannels( const DeviceRef &device ) +{ + if( device->getKey() == mDevices[0]->getKey() ) + return 2; + else + return 0; +} + +size_t DeviceManagerJack::getNumOutputChannels( const DeviceRef &device ) +{ + if( device->getKey() == mDevices[1]->getKey() ) + return 2; + else + return 0; +} + +size_t DeviceManagerJack::getSampleRate( const DeviceRef &device ) +{ + return mSampleRate; +} + +size_t DeviceManagerJack::getFramesPerBlock( const DeviceRef &device ) +{ + return mBufferSize; +} + + +void DeviceManagerJack::setSampleRate( const DeviceRef &device, size_t sampleRate ) +{ + throw "setSampleRate not supported"; +} + +void DeviceManagerJack::setFramesPerBlock( const DeviceRef &device, size_t framesPerBlock ) +{ + throw "setFramesPerBlock not supported"; +} + + +//! Returns the hardware's actual frames per block, which might not be a power of two. +// size_t getFramesPerBlockHardware( const DeviceRef &device ); +// + +size_t DeviceManagerJack::getFramesPerBlockHardware( const DeviceRef &device ) +{ + return mBufferSize; +} + + + + + + +} } } // namespace cinder::audio::linux
--- a/JackDevice/DeviceManagerJack.h Thu Jun 30 14:50:06 2016 +0200 +++ b/JackDevice/DeviceManagerJack.h Fri Jul 08 11:39:18 2016 +0200 @@ -1,61 +1,61 @@ -/* - Copyright (c) 2015, The Cinder Project - - This code is intended to be used with the Cinder C++ library, http://libcinder.org - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that - the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and - the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and - the following disclaimer in the documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#pragma once - -#include "cinder/audio/Device.h" - -namespace cinder { namespace audio { namespace linux { - -class DeviceManagerJack : public DeviceManager { - public: - - DeviceManagerJack(); - virtual ~DeviceManagerJack(); - - const std::vector<DeviceRef>& getDevices() override; - DeviceRef getDefaultOutput() override; - DeviceRef getDefaultInput() override; - - std::string getName( const DeviceRef &device ) override; - size_t getNumInputChannels( const DeviceRef &device ) override; - size_t getNumOutputChannels( const DeviceRef &device ) override; - size_t getSampleRate( const DeviceRef &device ) override; - size_t getFramesPerBlock( const DeviceRef &device ) override; - - void setSampleRate( const DeviceRef &device, size_t sampleRate ) override; - void setFramesPerBlock( const DeviceRef &device, size_t framesPerBlock ) override; - - //! Returns the hardware's actual frames per block, which might not be a power of two. - size_t getFramesPerBlockHardware( const DeviceRef &device ); - -private: - - std::vector<DeviceRef> mDevices; - DeviceRef mDefaultOutDevice; - DeviceRef mDefaultInDevice; - size_t mSampleRate; - size_t mBufferSize; -}; - -} } } // namespace cinder::audio::linux +/* + Copyright (c) 2015, The Cinder Project + + This code is intended to be used with the Cinder C++ library, http://libcinder.org + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that + the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and + the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + the following disclaimer in the documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once + +#include "cinder/audio/Device.h" + +namespace cinder { namespace audio { namespace linux { + +class DeviceManagerJack : public DeviceManager { + public: + + DeviceManagerJack(); + virtual ~DeviceManagerJack(); + + const std::vector<DeviceRef>& getDevices() override; + DeviceRef getDefaultOutput() override; + DeviceRef getDefaultInput() override; + + std::string getName( const DeviceRef &device ) override; + size_t getNumInputChannels( const DeviceRef &device ) override; + size_t getNumOutputChannels( const DeviceRef &device ) override; + size_t getSampleRate( const DeviceRef &device ) override; + size_t getFramesPerBlock( const DeviceRef &device ) override; + + void setSampleRate( const DeviceRef &device, size_t sampleRate ) override; + void setFramesPerBlock( const DeviceRef &device, size_t framesPerBlock ) override; + + //! Returns the hardware's actual frames per block, which might not be a power of two. + size_t getFramesPerBlockHardware( const DeviceRef &device ); + +private: + + std::vector<DeviceRef> mDevices; + DeviceRef mDefaultOutDevice; + DeviceRef mDefaultInDevice; + size_t mSampleRate; + size_t mBufferSize; +}; + +} } } // namespace cinder::audio::linux
--- a/TeensyCode/collidoscope_double_knob.ino Thu Jun 30 14:50:06 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,310 +0,0 @@ - -/****************************************************************************** - - * Ben Bengler - * mail@benbengler.com - * 02.05.2016 - * - * Collidoscope - * - * Teensy 2 ++ pinout: https://www.pjrc.com/teensy/card4b.pdf - * - * ANALOG INPUTS: - * Wavejet -> F0 (38) [Horizontal rail 1] - * Wavejet -> F1 (39) [Horizontal rail 2] - * Filter 1 -> F2 (40) [Vertical rail 1] - * Filter 2 -> F4 (42) [Vertical rail 2] - * - * DIGITAL INPUTS [INTERRUPTS]: - * Sel. length 1 -> INT0/INT1 (0, 1) [Encoder 1] - * Sel. length 2 -> INT2/INT3 (2, 3) [Encoder 2] - * Duration 1 -> INT4/INT5 (36, 37)[Encoder 3] - * Duration 2 -> INT6/INT7 (18, 19)[Encoder 4] - * - * DIGITAL INPUTS: - * Play1 toggle -> B0 (20) - * Record1 -> B1 (21) - * Play2 toggle -> B3 (22) - * Record2 -> B4 (24) - * - * DIGITAL OUTPUTS: - * Record Button 1 Led -> D4 (4) - * Record Button 2 Led -> D5 (5) - - ******************************************************************************/ - - -#include <Encoder.h> -#include <Bounce.h> - -/////////////////////////////////////////////////// -//MIDI settings -const int midi_chan_inst1 = 1; // MIDI channel for Instrument 1 -const int midi_chan_inst2 = 2; // MIDI channel for Instrument 2 - -const int cc_length = 1; // MIDI cc controlling selection length -const int cc_duration = 2; // MIDI cc controlling duration -const int cc_filter = 7; // MIDI cc controlling LP filter -const int cc_play = 4; // MIDI cc controlling PLAY -const int cc_record = 5; // MIDI cc controlling RECORD -//const int cc_reset = 100; // MIDI cc controlling instrument RESET - -/////////////////////////////////////////////////// -//Default Values: -const int Enc_def = 64; //default selection length -int MIDI_led_state = LOW; -//boolean reset1 = true; -//boolean reset2 = true; - -/////////////////////////////////////////////////// -// Interface Inputs - -//Buttons: - -const int Pin_play1 = 20; //B0 -const int Pin_record1 = 21; //B1 -const int Pin_play2 = 23; //B3 -const int Pin_record2 = 24; //B4 -const int Pin_record1_led = 4; //D4 -const int Pin_record2_led = 5; //D5 -const int Pin_MIDIled = 6; - -//const int Pin_reset1 = 22; //B2, not in use -//const int Pin_reset2 = 25; //B5, not in use - -Bounce button1 = Bounce(Pin_play1, 5); -Bounce button2 = Bounce(Pin_record1, 5); -Bounce button3 = Bounce(Pin_play2, 5); -Bounce button4 = Bounce(Pin_record2, 5); - - -//Encoder -Encoder Enc1 (0, 1); //Encoder for section length on Wavejet 1 -Encoder Enc2 (2, 3); //Encoder for section length on Wavejet 2 - - -// Variables -const int jitter_thresh = 10; //7threshold value for analog INs to suppress sending MIDI due to input jitter - -void setup() { - -pinMode(Pin_play1, INPUT_PULLUP); -pinMode(Pin_record1, INPUT_PULLUP); -pinMode(Pin_play2, INPUT_PULLUP); -pinMode(Pin_record2, INPUT_PULLUP); - - -pinMode(Pin_MIDIled, OUTPUT); -pinMode(Pin_record1_led, OUTPUT); -pinMode(Pin_record2_led, OUTPUT); -} - -//Store recent values to detect parameter change -long Enc1_old = -999; -long Enc2_old = -999; - -uint16_t Jet1_old = 0; -int16_t Jet1_old_MIDI = -1; -uint16_t Jet2_old = 0; -int16_t Jet2_old_MIDI = -1; - -uint16_t filter1_old = 0; -int16_t filter1_old_MIDI = -1; -uint16_t filter2_old = 0; -int16_t filter2_old_MIDI = -1; - -uint16_t dur1_old = 0; -int16_t dur1_old_MIDI = -1; -uint16_t dur2_old = 0; -int16_t dur2_old_MIDI = -1; - -void loop() { - - digitalWrite(Pin_MIDIled, LOW); - digitalWrite(Pin_record1_led, HIGH); - digitalWrite(Pin_record2_led, HIGH); - button1.update(); - button2.update(); - button3.update(); - button4.update(); - - - uint16_t Jet1_new = analogRead(0); //read Wavejet/Rail 1 - uint16_t Jet2_new = analogRead(1); //read Wavejet/Rail 2 - uint16_t filter1_new = analogRead(2); //read filter Instrument 1; ADJUST INPUT RANGE ACCORDING TO SENSOR - uint16_t filter2_new = analogRead(4); //read filter Instrument 2; ADJUST INPUT RANGE ACCORDING TO SENSOR - uint16_t dur1_new = analogRead(3); - uint16_t dur2_new = analogRead(5); - - - //Encoder 1 [Controls selection length of wave 1] - long Enc1_new = Enc1.read(); - Enc1_new = constrain(Enc1_new, 0, 127); //constrain to 7-bit MIDI range - - //Dynamic reset of counter to MIDI range - if (Enc1_new <= 0){ - Enc1.write(0); - } - else if (Enc1_new >= 127){ - Enc1.write(127); - } - - //Encoder 2 [Controls selection length of wave 2] - long Enc2_new = Enc2.read(); - Enc2_new = constrain(Enc2_new, 0, 127); //constrain to 7-bit MIDI range - - //Dynamic reset of counter to MIDI range - if (Enc2_new <= 0){ - Enc2.write(0); - } - else if (Enc2_new >= 127){ - Enc2.write(127); - } - - //Instrument 1 Controls////////////////////////////////////// - - //Loop/Keymode Switch Instrument 1 - - if (button1.risingEdge()) { - //Serial.println("Loop mode"); - usbMIDI.sendControlChange(cc_play, 1, midi_chan_inst1); - } - - if (button1.fallingEdge()) { - //Serial.println("Keyboardmode mode"); - usbMIDI.sendControlChange(cc_play, 0, midi_chan_inst1); - } - - - //Record Instrument 1 - if (button2.fallingEdge()) { - //Serial.println("RECORD! Instrument 1"); - usbMIDI.sendControlChange(cc_record, 1, midi_chan_inst1); - } - - //send MIDI Wavejet 1 [Position Instrument 1] - - if (Jet1_new > Jet1_old+jitter_thresh || Jet1_new < Jet1_old-jitter_thresh) { - - int16_t midiVal = constrain( map(Jet1_new, 24, 926, 0, 149), 0, 149 ); - // int16_t midiVal = constrain( map( Jet1_new, 23, 928, 0, 149 ), 0, 149 ); old collidoscope - if( midiVal != Jet1_old_MIDI ){ - Jet1_old_MIDI = midiVal; - usbMIDI.sendPitchBend( midiVal, midi_chan_inst1 ); - } - - Jet1_old = Jet1_new; - digitalWrite(Pin_MIDIled, HIGH); - } - - - //send MIDI Filter 1 [Filter Instrument 1] - - if ( filter1_new != filter1_old ) { // maybe adding jitter threshold needed, see Jet1_new - - int16_t midiVal = constrain( map(filter1_new, 0, 1024, 0, 127), 0, 127 ); - if( midiVal != filter1_old_MIDI){ - //Serial.println( midiVal ); - filter1_old_MIDI = midiVal; - usbMIDI.sendControlChange(cc_filter, midiVal, midi_chan_inst1); - } - - filter1_old = filter1_new; - digitalWrite(Pin_MIDIled, HIGH); - } - - if ( dur1_new != dur1_old ) { // maybe adding jitter threshold needed, see Jet1_new - - int16_t midiVal = constrain( map(dur1_new, 0, 1024, 0, 127), 0, 127 ); - if( midiVal != dur1_old_MIDI){ - //Serial.println( midiVal ); - dur1_old_MIDI = midiVal; - usbMIDI.sendControlChange(cc_duration, midiVal, midi_chan_inst1); - } - - dur1_old = dur1_new; - digitalWrite(Pin_MIDIled, HIGH); - } - - //send MIDI Encoder 1 [Selection length Instrument 1] - if (Enc1_new != Enc1_old) { - Enc1_old = Enc1_new; - //Serial.println("Encoder 1: "); - //Serial.println(Enc1_new); - usbMIDI.sendControlChange(cc_length, Enc1_new, midi_chan_inst1); - digitalWrite(Pin_MIDIled, HIGH); - } - - - - //Instrument 2 Controls////////////////////////////////////// - - //Loop/Keymode Switch Instrument 2 - - if (button3.risingEdge()) { - //Serial.println("Loop mode"); - usbMIDI.sendControlChange(cc_play, 1, midi_chan_inst2); - } - - if (button3.fallingEdge()) { - //Serial.println("Keyboardmode mode"); - usbMIDI.sendControlChange(cc_play, 0, midi_chan_inst2); - } - - //Record Instrument 2 - if (button4.fallingEdge()) { - //Serial.println("RECORD! Instrument 2"); - usbMIDI.sendControlChange(cc_record, 1, midi_chan_inst2); - } - - //send MIDI Wavejet 2 [Position Instrument 2] - - if (Jet2_new > Jet2_old+jitter_thresh || Jet2_new < Jet2_old-jitter_thresh) { - //Serial.println("RECORD! Instrument 2"); - int16_t midiVal = constrain( map( Jet2_new, 925, 18, 149, 0 ), 0, 149 ); - if( midiVal != Jet2_old_MIDI ){ - Jet2_old_MIDI = midiVal; - usbMIDI.sendPitchBend( midiVal, midi_chan_inst2 ); - } - - Jet2_old = Jet2_new; - digitalWrite(Pin_MIDIled, HIGH); - } - - //Serial.println(filter2_new); - if ( filter2_new != filter2_old ) { // maybe adding jitter threshold needed, see Jet1_new - int16_t midiVal = constrain( map(filter2_new, 0, 1024, 0, 127), 0, 127 ); - if( midiVal != filter2_old_MIDI){ - //Serial.println( midiVal ); - filter2_old_MIDI = midiVal; - usbMIDI.sendControlChange(cc_filter, midiVal, midi_chan_inst2); - } - - filter2_old = filter2_new; - digitalWrite(Pin_MIDIled, HIGH); - } - - if ( dur2_new != dur2_old ) { // maybe adding jitter threshold needed, see Jet1_new - int16_t midiVal = constrain( map(dur2_new, 0, 1024, 0, 127), 0, 127 ); - if( midiVal != dur2_old_MIDI){ - //Serial.println( midiVal ); - dur2_old_MIDI = midiVal; - usbMIDI.sendControlChange(cc_duration, midiVal, midi_chan_inst2); - } - - dur2_old = dur2_new; - digitalWrite(Pin_MIDIled, HIGH); - } - - - //send MIDI Encoder 2 [Selection length Instrument 2] - if (Enc2_new != Enc2_old) { - Enc2_old = Enc2_new; - //Serial.println("Encoder 2: "); - //Serial.println(Enc2_new); - usbMIDI.sendControlChange(cc_length, Enc2_new, midi_chan_inst2); - digitalWrite(Pin_MIDIled, HIGH); - } - -} -
--- a/TeensyCode/collidoscope_single_knob.ino Thu Jun 30 14:50:06 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,310 +0,0 @@ - -/****************************************************************************** - - * Ben Bengler - * mail@benbengler.com - * 02.05.2016 - * - * Collidoscope - * - * Teensy 2 ++ pinout: https://www.pjrc.com/teensy/card4b.pdf - * - * ANALOG INPUTS: - * Wavejet -> F0 (38) [Horizontal rail 1] - * Wavejet -> F1 (39) [Horizontal rail 2] - * Filter 1 -> F2 (40) [Vertical rail 1] - * Filter 2 -> F4 (42) [Vertical rail 2] - * - * DIGITAL INPUTS [INTERRUPTS]: - * Sel. length 1 -> INT0/INT1 (0, 1) [Encoder 1] - * Sel. length 2 -> INT2/INT3 (2, 3) [Encoder 2] - * Duration 1 -> INT4/INT5 (36, 37)[Encoder 3] - * Duration 2 -> INT6/INT7 (18, 19)[Encoder 4] - * - * DIGITAL INPUTS: - * Play1 toggle -> B0 (20) - * Record1 -> B1 (21) - * Play2 toggle -> B3 (22) - * Record2 -> B4 (24) - * - * DIGITAL OUTPUTS: - * Record Button 1 Led -> D4 (4) - * Record Button 2 Led -> D5 (5) - - ******************************************************************************/ - - -#include <Encoder.h> -#include <Bounce.h> - -/////////////////////////////////////////////////// -//MIDI settings -const int midi_chan_inst1 = 1; // MIDI channel for Instrument 1 -const int midi_chan_inst2 = 2; // MIDI channel for Instrument 2 - -const int cc_length = 1; // MIDI cc controlling selection length -const int cc_duration = 2; // MIDI cc controlling duration -const int cc_filter = 7; // MIDI cc controlling LP filter -const int cc_play = 4; // MIDI cc controlling PLAY -const int cc_record = 5; // MIDI cc controlling RECORD -//const int cc_reset = 100; // MIDI cc controlling instrument RESET - -/////////////////////////////////////////////////// -//Default Values: -const int Enc_def = 64; //default selection length -int MIDI_led_state = LOW; -//boolean reset1 = true; -//boolean reset2 = true; - -/////////////////////////////////////////////////// -// Interface Inputs - -//Buttons: - -const int Pin_play1 = 20; //B0 -const int Pin_record1 = 21; //B1 -const int Pin_play2 = 23; //B3 -const int Pin_record2 = 24; //B4 -const int Pin_record1_led = 4; //D4 -const int Pin_record2_led = 5; //D5 -const int Pin_MIDIled = 6; - -//const int Pin_reset1 = 22; //B2, not in use -//const int Pin_reset2 = 25; //B5, not in use - -Bounce button1 = Bounce(Pin_play1, 5); -Bounce button2 = Bounce(Pin_record1, 5); -Bounce button3 = Bounce(Pin_play2, 5); -Bounce button4 = Bounce(Pin_record2, 5); - - -//Encoder -Encoder Enc1 (0, 1); //Encoder for section length on Wavejet 1 -Encoder Enc2 (2, 3); //Encoder for section length on Wavejet 2 - - -// Variables -const int jitter_thresh = 10; //7threshold value for analog INs to suppress sending MIDI due to input jitter - -void setup() { - -pinMode(Pin_play1, INPUT_PULLUP); -pinMode(Pin_record1, INPUT_PULLUP); -pinMode(Pin_play2, INPUT_PULLUP); -pinMode(Pin_record2, INPUT_PULLUP); - - -pinMode(Pin_MIDIled, OUTPUT); -pinMode(Pin_record1_led, OUTPUT); -pinMode(Pin_record2_led, OUTPUT); -} - -//Store recent values to detect parameter change -long Enc1_old = -999; -long Enc2_old = -999; - -uint16_t Jet1_old = 0; -int16_t Jet1_old_MIDI = -1; -uint16_t Jet2_old = 0; -int16_t Jet2_old_MIDI = -1; - -uint16_t filter1_old = 0; -int16_t filter1_old_MIDI = -1; -uint16_t filter2_old = 0; -int16_t filter2_old_MIDI = -1; - -uint16_t dur1_old = 0; -int16_t dur1_old_MIDI = -1; -uint16_t dur2_old = 0; -int16_t dur2_old_MIDI = -1; - -void loop() { - - digitalWrite(Pin_MIDIled, LOW); - digitalWrite(Pin_record1_led, HIGH); - digitalWrite(Pin_record2_led, HIGH); - button1.update(); - button2.update(); - button3.update(); - button4.update(); - - - uint16_t Jet1_new = analogRead(0); //read Wavejet/Rail 1 - uint16_t Jet2_new = analogRead(1); //read Wavejet/Rail 2 - uint16_t filter1_new = analogRead(2); //read filter Instrument 1; ADJUST INPUT RANGE ACCORDING TO SENSOR - uint16_t filter2_new = analogRead(4); //read filter Instrument 2; ADJUST INPUT RANGE ACCORDING TO SENSOR - uint16_t dur1_new = analogRead(3); - uint16_t dur2_new = analogRead(5); - - - //Encoder 1 [Controls selection length of wave 1] - long Enc1_new = Enc1.read(); - Enc1_new = constrain(Enc1_new, 0, 127); //constrain to 7-bit MIDI range - - //Dynamic reset of counter to MIDI range - if (Enc1_new <= 0){ - Enc1.write(0); - } - else if (Enc1_new >= 127){ - Enc1.write(127); - } - - //Encoder 2 [Controls selection length of wave 2] - long Enc2_new = Enc2.read(); - Enc2_new = constrain(Enc2_new, 0, 127); //constrain to 7-bit MIDI range - - //Dynamic reset of counter to MIDI range - if (Enc2_new <= 0){ - Enc2.write(0); - } - else if (Enc2_new >= 127){ - Enc2.write(127); - } - - //Instrument 1 Controls////////////////////////////////////// - - //Loop/Keymode Switch Instrument 1 - - if (button1.risingEdge()) { - //Serial.println("Loop mode"); - usbMIDI.sendControlChange(cc_play, 1, midi_chan_inst1); - } - - if (button1.fallingEdge()) { - //Serial.println("Keyboardmode mode"); - usbMIDI.sendControlChange(cc_play, 0, midi_chan_inst1); - } - - - //Record Instrument 1 - if (button2.fallingEdge()) { - //Serial.println("RECORD! Instrument 1"); - usbMIDI.sendControlChange(cc_record, 1, midi_chan_inst1); - } - - //send MIDI Wavejet 1 [Position Instrument 1] - - if (Jet1_new > Jet1_old+jitter_thresh || Jet1_new < Jet1_old-jitter_thresh) { - - int16_t midiVal = constrain( map(Jet1_new, 24, 926, 0, 149), 0, 149 ); - // int16_t midiVal = constrain( map( Jet1_new, 23, 928, 0, 149 ), 0, 149 ); old collidoscope - if( midiVal != Jet1_old_MIDI ){ - Jet1_old_MIDI = midiVal; - usbMIDI.sendPitchBend( midiVal, midi_chan_inst1 ); - } - - Jet1_old = Jet1_new; - digitalWrite(Pin_MIDIled, HIGH); - } - - - //send MIDI Filter 1 [Filter Instrument 1] - - if ( filter1_new != filter1_old ) { // maybe adding jitter threshold needed, see Jet1_new - - int16_t midiVal = constrain( map(filter1_new, 0, 1024, 0, 127), 0, 127 ); - if( midiVal != filter1_old_MIDI){ - //Serial.println( midiVal ); - filter1_old_MIDI = midiVal; - usbMIDI.sendControlChange(cc_filter, midiVal, midi_chan_inst1); - } - - filter1_old = filter1_new; - digitalWrite(Pin_MIDIled, HIGH); - } - - if ( dur1_new != dur1_old ) { // maybe adding jitter threshold needed, see Jet1_new - - int16_t midiVal = constrain( map(dur1_new, 0, 1024, 0, 127), 0, 127 ); - if( midiVal != dur1_old_MIDI){ - //Serial.println( midiVal ); - dur1_old_MIDI = midiVal; - usbMIDI.sendControlChange(cc_duration, midiVal, midi_chan_inst1); - } - - dur1_old = dur1_new; - digitalWrite(Pin_MIDIled, HIGH); - } - - //send MIDI Encoder 1 [Selection length Instrument 1] - if (Enc1_new != Enc1_old) { - Enc1_old = Enc1_new; - //Serial.println("Encoder 1: "); - //Serial.println(Enc1_new); - usbMIDI.sendControlChange(cc_length, Enc1_new, midi_chan_inst1); - digitalWrite(Pin_MIDIled, HIGH); - } - - - - //Instrument 2 Controls////////////////////////////////////// - - //Loop/Keymode Switch Instrument 2 - - if (button3.risingEdge()) { - //Serial.println("Loop mode"); - usbMIDI.sendControlChange(cc_play, 1, midi_chan_inst2); - } - - if (button3.fallingEdge()) { - //Serial.println("Keyboardmode mode"); - usbMIDI.sendControlChange(cc_play, 0, midi_chan_inst2); - } - - //Record Instrument 2 - if (button4.fallingEdge()) { - //Serial.println("RECORD! Instrument 2"); - usbMIDI.sendControlChange(cc_record, 1, midi_chan_inst2); - } - - //send MIDI Wavejet 2 [Position Instrument 2] - - if (Jet2_new > Jet2_old+jitter_thresh || Jet2_new < Jet2_old-jitter_thresh) { - //Serial.println("RECORD! Instrument 2"); - int16_t midiVal = constrain( map( Jet2_new, 925, 18, 149, 0 ), 0, 149 ); - if( midiVal != Jet2_old_MIDI ){ - Jet2_old_MIDI = midiVal; - usbMIDI.sendPitchBend( midiVal, midi_chan_inst2 ); - } - - Jet2_old = Jet2_new; - digitalWrite(Pin_MIDIled, HIGH); - } - - //Serial.println(filter2_new); - if ( filter2_new != filter2_old ) { // maybe adding jitter threshold needed, see Jet1_new - int16_t midiVal = constrain( map(filter2_new, 0, 1024, 0, 127), 0, 127 ); - if( midiVal != filter2_old_MIDI){ - //Serial.println( midiVal ); - filter2_old_MIDI = midiVal; - usbMIDI.sendControlChange(cc_filter, midiVal, midi_chan_inst2); - } - - filter2_old = filter2_new; - digitalWrite(Pin_MIDIled, HIGH); - } - - if ( dur2_new != dur2_old ) { // maybe adding jitter threshold needed, see Jet1_new - int16_t midiVal = constrain( map(dur2_new, 0, 1024, 0, 127), 0, 127 ); - if( midiVal != dur2_old_MIDI){ - //Serial.println( midiVal ); - dur2_old_MIDI = midiVal; - usbMIDI.sendControlChange(cc_duration, midiVal, midi_chan_inst2); - } - - dur2_old = dur2_new; - digitalWrite(Pin_MIDIled, HIGH); - } - - - //send MIDI Encoder 2 [Selection length Instrument 2] - if (Enc2_new != Enc2_old) { - Enc2_old = Enc2_new; - //Serial.println("Encoder 2: "); - //Serial.println(Enc2_new); - usbMIDI.sendControlChange(cc_length, Enc2_new, midi_chan_inst2); - digitalWrite(Pin_MIDIled, HIGH); - } - -} -