├── data ├── MakeFile └── test │ ├── SRAMHWMock.h │ ├── Makefile │ ├── DummyStepMemory.h │ ├── SRAMHWMock.cpp │ └── DummyStepMemory.cpp ├── Step.cpp ├── .gitignore ├── SequenceDataTypeEnum.h ├── test ├── testAverage.sh ├── testMapping.sh ├── testStepper.sh ├── testTapper.sh ├── HWLayerMock.h ├── testLFO.sh ├── mapping.plt ├── HWLayerMock.cpp ├── testMapping.cpp ├── FiFoBuffer-Test.cpp ├── testAverage.cpp ├── testStepper.cpp ├── testTapper.cpp ├── Makefile ├── tstSwitches.cpp ├── tstRadioButton.cpp └── data │ └── lfo.plt ├── LEDsAndButtonsHWWrapper.cpp ├── StepSynchronizer.cpp ├── IMIDICommandProcessor.h ├── random.h ├── IView.h ├── DrumStep.cpp ├── ILEDHW.h ├── MIDICommand.cpp ├── players └── test │ ├── MIDICommandProcessorMock.cpp │ ├── MIDICommandProcessorMock.h │ ├── Makefile │ └── tst.cpp ├── LEDRadioButtons.h ├── debugSwitch.h ├── IButtonHW.h ├── Step.h ├── ILEDsAndButtonsHW.h ├── modules └── test │ ├── SteppingHWLayerMock.cpp │ ├── Makefile │ ├── SteppingHWLayerMock.h │ └── tst.cpp ├── BPMConverter.h ├── ITapper.h ├── BitArrayOperations.cpp ├── LEDRadioButtons.cpp ├── LEDsAndButtonsHWWrapper.h ├── basic.h ├── random.cpp ├── RackInstrumentDefinitions.h ├── LFOSimple.h ├── runAllTests.sh ├── spiShared.h ├── RadioButtons.h ├── BPMConverter.cpp ├── BitArrayOperations.h ├── simpleSerialProtocol.h ├── LFORandom.h ├── MIDIStepper.h ├── MIDIStepper.cpp ├── .settings └── de.innot.avreclipse.core.prefs ├── LFO.h ├── ArduinoMIDICommandProcessor.h ├── StepSynchronizer.h ├── fastAnalogRead.h ├── MIDInoteBuffer.h ├── ArduinoMIDICommandProcessor.cpp ├── IStepMemory.h ├── LFO.cpp ├── simpleSerialProtocol.cpp ├── StepRecorder.h ├── SimplifiedTapper.h ├── DrumStep.h ├── FlashStepMemory.h ├── interpolatingBuffer.h ├── LFOSimple.cpp ├── BastlMetronome.h ├── MIDICommand.h ├── shiftRegisters.cpp ├── IHWLayer.h ├── RadioButtons.cpp ├── Tapper.h ├── portManipulations.h ├── Switches.h ├── Switches.cpp ├── SimplifiedTapper.cpp ├── shiftRegisters.h ├── LFORandom.cpp ├── NoVelocityStepMemory.h ├── expADSR.cpp ├── fastArithmetic.h ├── BastlMetronome.cpp ├── readme.txt ├── FiFoBuffer.h ├── movingAverage.h ├── shiftRegisterFast.h ├── Arpeggiator.h ├── interpolatingBuffer.cpp ├── MIDInoteBuffer.cpp ├── PlayerSettings.cpp ├── lfoExtended.h ├── Stepper.h ├── simpleSerialDecoder.h ├── expADSR.h ├── stateHandler.h ├── Tapper.cpp ├── Arpeggiator.cpp ├── StepRecorder.cpp ├── Player.h ├── Player.cpp ├── trinityRack_HW.h ├── lfoExtended.cpp ├── mapping.h ├── FlashStepMemory.cpp ├── eepromObject.h └── NoVelocityStepMemory.cpp /data/MakeFile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Step.cpp: -------------------------------------------------------------------------------- 1 | #include "Step.h" 2 | 3 | Step::Step( bool mute) : _mute(mute) { 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | test/*.o 3 | test/build 4 | test/obj 5 | test/*.pdf 6 | test/*.log 7 | test/*.csv 8 | test/*.png 9 | -------------------------------------------------------------------------------- /SequenceDataTypeEnum.h: -------------------------------------------------------------------------------- 1 | #ifndef SEQUENCEDATATYPEENUM_H 2 | #define SEQUENCEDATATYPEENUM_H 3 | 4 | #endif // SEQUENCEDATATYPEENUM_H 5 | -------------------------------------------------------------------------------- /test/testAverage.sh: -------------------------------------------------------------------------------- 1 | rm runAverage 2 | rm testAverage.o 3 | 4 | g++ -c -o testAverage.o testAverage.cpp 5 | g++ -o runAverage testAverage.o 6 | ./runAverage 7 | -------------------------------------------------------------------------------- /test/testMapping.sh: -------------------------------------------------------------------------------- 1 | rm runMapping 2 | rm testMapping.o 3 | 4 | g++ -DTESTING -c -o testMapping.o testMapping.cpp 5 | g++ -o runMapping testMapping.o 6 | ./runMapping > mapping.csv 7 | gnuplot mapping.plt 8 | -------------------------------------------------------------------------------- /test/testStepper.sh: -------------------------------------------------------------------------------- 1 | rm *.o 2 | rm data/*.csv 3 | rm stepper 4 | 5 | g++ -c -DTESTING -Wall -o stepperTest.o testStepper.cpp 6 | g++ -o ./stepper stepperTest.o 7 | ./stepper 8 | cd data 9 | gnuplot stepper.plt 10 | -------------------------------------------------------------------------------- /test/testTapper.sh: -------------------------------------------------------------------------------- 1 | rm runTapper 2 | rm testTapper.o 3 | rm tapper.o 4 | 5 | g++ -c -o testTapper.o testTapper.cpp 6 | g++ -c -DTESTING -o tapper.o ../Tapper.cpp 7 | g++ -o runTapper testTapper.o tapper.o 8 | ./runTapper 9 | -------------------------------------------------------------------------------- /LEDsAndButtonsHWWrapper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * LEDsAndButtonsHWWrapper.cpp 3 | * 4 | * Created on: 10 Oct 2017 5 | * Author: gaardnab 6 | */ 7 | 8 | #include 9 | 10 | ILEDsAndButtonsHW * LEDsAndButtonsHWWrapper::hw_ = 0; 11 | -------------------------------------------------------------------------------- /StepSynchronizer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * StepSynchronizer.cpp 3 | * 4 | * Created on: Sep 12, 2014 5 | * Author: bastl 6 | */ 7 | 8 | #include "StepSynchronizer.h" 9 | 10 | StepSynchronizer::StepSynchronizer() : cycleLength_(256), currentStepNumber_ (0), waiting_(true) { 11 | } 12 | -------------------------------------------------------------------------------- /IMIDICommandProcessor.h: -------------------------------------------------------------------------------- 1 | #ifndef IMIDICOMMANDPROCESSOR_H 2 | #define IMIDICOMMANDPROCESSOR_H 3 | 4 | #include "MIDICommand.h" 5 | 6 | class IMIDICommandProcessor { 7 | public: 8 | virtual void SendCommand(MIDICommand & command) = 0; 9 | }; 10 | 11 | #endif // IMIDICOMMANDPROCESSOR_H 12 | -------------------------------------------------------------------------------- /random.h: -------------------------------------------------------------------------------- 1 | /* 2 | * random.h 3 | * 4 | * Created on: 10.11.2014 5 | * Author: user 6 | */ 7 | 8 | #ifndef RANDOM_H_ 9 | #define RANDOM_H_ 10 | 11 | #include 12 | 13 | namespace bastlRandom { 14 | uint8_t byte(); 15 | uint8_t range(uint8_t min, uint8_t max); 16 | } 17 | #endif 18 | -------------------------------------------------------------------------------- /IView.h: -------------------------------------------------------------------------------- 1 | /* 2 | * IView.h 3 | * 4 | * Created on: Jul 25, 2014 5 | * Author: bastl 6 | */ 7 | 8 | #ifndef IVIEW_H_ 9 | #define IVIEW_H_ 10 | 11 | class IView { 12 | public: 13 | virtual ~IView() = 0; 14 | virtual void update() = 0; 15 | }; 16 | 17 | inline IView::~IView() { } 18 | 19 | #endif /* IVIEW_H_ */ 20 | 21 | -------------------------------------------------------------------------------- /DrumStep.cpp: -------------------------------------------------------------------------------- 1 | #include "DrumStep.h" 2 | 3 | DrumStep::DrumStep() : Step(false) { 4 | for (int i = 0; i < 4; i++) { 5 | _substeps[i] = OFF; 6 | } 7 | } 8 | 9 | DrumStep::DrumStep(bool mute, DrumVelocityType substeps[]) : Step(mute) 10 | { 11 | for (int i = 0; i < 4; i++) { 12 | _substeps[i] = substeps[i]; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ILEDHW.h: -------------------------------------------------------------------------------- 1 | #ifndef ILEDHW_H 2 | #define ILEDHW_H 3 | 4 | #define BUTTON_DRUM_1 16 5 | #define BUTTON_DRUM_2 17 6 | #define BUTTON_DRUM_3 18 7 | 8 | #include 9 | 10 | class ILEDHW { 11 | public: 12 | 13 | enum LedState{ON=255,OFF=0, BLINK, BLINK_INVERT, DULLON}; 14 | 15 | // LEDs // 16 | virtual void setLED(uint8_t index, LedState state) = 0; 17 | 18 | }; 19 | 20 | #endif // ILEDHW_H 21 | -------------------------------------------------------------------------------- /MIDICommand.cpp: -------------------------------------------------------------------------------- 1 | #include "MIDICommand.h" 2 | 3 | MIDICommand::MIDICommand() : type_(NOTEOFF), channel_(0), note_(0), velocity_(0) { 4 | } 5 | 6 | 7 | MIDICommand::MIDICommand(MIDICommand::MIDICommandType type, 8 | unsigned char channel, 9 | unsigned char note, 10 | unsigned char velocity) : 11 | type_(type), channel_(channel), note_(note), velocity_(velocity) 12 | { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /test/HWLayerMock.h: -------------------------------------------------------------------------------- 1 | #ifndef HWLAYERMOCK_H 2 | #define HWLAYERMOCK_H 3 | 4 | #include "../IButtonHW.h" 5 | 6 | class HWLayerMock : public IButtonHW 7 | { 8 | public: 9 | HWLayerMock(); 10 | 11 | virtual IButtonHW::ButtonState getButtonState(unsigned char index); 12 | void setButtonState(unsigned char buttonIndex, bool newState); 13 | private: 14 | bool buttonStates_[32]; 15 | 16 | }; 17 | 18 | #endif // HWLAYERMOCK_H 19 | -------------------------------------------------------------------------------- /players/test/MIDICommandProcessorMock.cpp: -------------------------------------------------------------------------------- 1 | #include "MIDICommandProcessorMock.h" 2 | 3 | MIDICommandProcessorMock::MIDICommandProcessorMock() 4 | { 5 | clear(); 6 | } 7 | 8 | void MIDICommandProcessorMock::SendCommand(MIDICommand &command) 9 | { 10 | if (command.getType() == MIDICommand::NOTEOFF) { 11 | noteOffCount_[command.getChannel()]++; 12 | } else { 13 | noteOnCount_[command.getChannel()]++; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /LEDRadioButtons.h: -------------------------------------------------------------------------------- 1 | #ifndef LEDRADIOBUTTONS_H 2 | #define LEDRADIOBUTTONS_H 3 | 4 | 5 | #include "ILEDsAndButtonsHW.h" 6 | #include "RadioButtons.h" 7 | 8 | class LEDRadioButtons : public RadioButtons 9 | { 10 | public: 11 | virtual void init(unsigned char * buttonIndexes, unsigned char count); 12 | virtual void setSelectedButton(unsigned char selectedButton); 13 | virtual void resetSelection(); 14 | }; 15 | 16 | #endif // LEDRADIOBUTTONS_H 17 | -------------------------------------------------------------------------------- /debugSwitch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * debugSwitch.h 3 | * 4 | * Created on: 05.07.2014 5 | * Author: user 6 | */ 7 | 8 | #ifndef DEBUGSWITCH_H_ 9 | #define DEBUGSWITCH_H_ 10 | 11 | 12 | // enclose your debug routines by this macro to quickyl turn them on or off 13 | // DBGS debug start 14 | // DBGE debug end 15 | 16 | #define DEBUG 0 17 | 18 | #define DBGS if(DEBUG) { 19 | #define DBGE } 20 | 21 | 22 | 23 | 24 | #endif /* DEBUGSWITCH_H_ */ 25 | -------------------------------------------------------------------------------- /test/testLFO.sh: -------------------------------------------------------------------------------- 1 | rm *.o 2 | rm data/*.csv 3 | rm lfo 4 | 5 | g++ -c -DTESTING -Wall -o testLFO.o testLFO.cpp 6 | g++ -c -DTESTING -Wall -o random.o ../random.cpp 7 | g++ -c -DTESTING -Wall -o LFO.o ../LFO.cpp 8 | g++ -c -DTESTING -Wall -o LFOSimple.o ../LFOSimple.cpp 9 | g++ -c -DTESTING -Wall -o LFORandom.o ../LFORandom.cpp 10 | g++ -o ./lfo testLFO.o random.o LFO.o LFOSimple.o LFORandom.o 11 | ./lfo 12 | cd data 13 | gnuplot lfo.plt 14 | 15 | -------------------------------------------------------------------------------- /IButtonHW.h: -------------------------------------------------------------------------------- 1 | /* 2 | * IButtonHW.h 3 | * 4 | * Created on: Dec 12, 2014 5 | * Author: martin 6 | */ 7 | 8 | #ifndef IBUTTONHW_H_ 9 | #define IBUTTONHW_H_ 10 | 11 | #include 12 | 13 | class IButtonHW { 14 | public: 15 | 16 | enum ButtonState{UP, DOWN}; 17 | 18 | virtual ButtonState getButtonState(unsigned char index) = 0; 19 | virtual bool isButtonDown(unsigned char index) = 0; 20 | 21 | }; 22 | 23 | #endif /* IBUTTONHW_H_ */ 24 | -------------------------------------------------------------------------------- /Step.h: -------------------------------------------------------------------------------- 1 | #ifndef SEQUENCEMESSAGE_H 2 | #define SEQUENCEMESSAGE_H 3 | 4 | class Step { 5 | public: 6 | enum InstrumentType {DRUM, MONO, POLY}; 7 | 8 | Step( bool mute); 9 | bool isMuted(); 10 | void setMuted(bool muted); 11 | private: 12 | bool _mute; 13 | }; 14 | 15 | inline bool Step::isMuted() { 16 | return _mute; 17 | } 18 | 19 | inline void Step::setMuted(bool mute) { 20 | _mute = mute; 21 | } 22 | 23 | #endif // SEQUENCEMESSAGE_H 24 | -------------------------------------------------------------------------------- /test/mapping.plt: -------------------------------------------------------------------------------- 1 | set xrange [0:256] 2 | set xtics 64 3 | set key outside right 4 | 5 | set terminal pdfcairo 6 | set output "mapping.pdf" 7 | 8 | plot "mapping.csv" using 1:2 with lines,\ 9 | "mapping.csv" using 1:3 with lines,\ 10 | "mapping.csv" using 1:4 with lines,\ 11 | "mapping.csv" using 1:5 with lines,\ 12 | "mapping.csv" using 1:6 with lines,\ 13 | "mapping.csv" using 1:7 with lines,\ 14 | "mapping.csv" using 1:8 with lines,\ 15 | "mapping.csv" using 1:9 with lines 16 | -------------------------------------------------------------------------------- /ILEDsAndButtonsHW.h: -------------------------------------------------------------------------------- 1 | #ifndef ILEDSANDBUTTONSHW_H 2 | #define ILEDSANDBUTTONSHW_H 3 | 4 | #include 5 | #include "ILEDHW.h" 6 | #include "IButtonHW.h" 7 | 8 | class ILEDsAndButtonsHW : public ILEDHW, public IButtonHW { 9 | public: 10 | 11 | enum TriggerState{GATE_ON, GATE_OFF, TRIGGER_ON}; 12 | 13 | virtual uint16_t getElapsedBastlCycles() = 0; 14 | virtual void setTrigger(uint8_t number, bool state,bool autoOff) = 0; 15 | }; 16 | 17 | #endif // ILEDSANDBUTTONSHW_H 18 | -------------------------------------------------------------------------------- /modules/test/SteppingHWLayerMock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SteppingHWLayerMock.cpp 3 | * 4 | * Created on: Jul 16, 2014 5 | * Author: bastl 6 | */ 7 | 8 | #include "SteppingHWLayerMock.h" 9 | 10 | void SteppingHWLayerMock::setBastlCyclesPerSecond(unsigned int bastlCyclesPerSecond) { 11 | bastlCyclesPerSecond_ = bastlCyclesPerSecond; 12 | } 13 | 14 | void SteppingHWLayerMock::setElapsedBastlCycles(unsigned int elapsedBastlCycles) { 15 | elapsedBastlCycles_ = elapsedBastlCycles; 16 | } 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/HWLayerMock.cpp: -------------------------------------------------------------------------------- 1 | #include "HWLayerMock.h" 2 | 3 | HWLayerMock::HWLayerMock() 4 | { 5 | for (unsigned char i = 0; i < 32; i++) { 6 | buttonStates_[i] = false; 7 | } 8 | } 9 | 10 | IButtonHW::ButtonState HWLayerMock::getButtonState(unsigned char index) 11 | { 12 | return buttonStates_[index] ? IButtonHW::DOWN : IButtonHW::UP ; 13 | } 14 | 15 | void HWLayerMock::setButtonState(unsigned char buttonIndex, bool newState) 16 | { 17 | buttonStates_[buttonIndex] = newState; 18 | } 19 | -------------------------------------------------------------------------------- /BPMConverter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BPMConverter.h 3 | * 4 | * Created on: Sep 12, 2014 5 | * Author: bastl 6 | */ 7 | 8 | #ifndef BPMCONVERTER_H_ 9 | #define BPMCONVERTER_H_ 10 | 11 | #include 12 | 13 | class BPMConverter { 14 | public: 15 | static uint16_t bpmToTimeUnits(uint16_t bpm, uint16_t timeUnitsPerSecond, uint16_t sourceLeftOvers, uint16_t & leftOvers); 16 | static uint16_t timeUnitsToBPM(uint16_t timeUnits, uint16_t timeUnitsPerSecond); 17 | }; 18 | 19 | #endif /* BPMCONVERTER_H_ */ 20 | -------------------------------------------------------------------------------- /ITapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ITapper.h 3 | * 4 | * Created on: Dec 26, 2014 5 | * Author: martin 6 | */ 7 | 8 | #ifndef ITAPPER_H_ 9 | #define ITAPPER_H_ 10 | 11 | #include 12 | 13 | class ITapper { 14 | public: 15 | virtual void tap(uint16_t tapTime) = 0; 16 | virtual void setStepsPerTap(uint8_t stepsPerTap) = 0; 17 | virtual uint16_t getTimeUnitsPerStep() = 0; 18 | virtual void setStepCallBack(void (*makeStep)()) = 0; 19 | virtual bool anyStepDetected() = 0; 20 | 21 | }; 22 | 23 | 24 | #endif /* ITAPPER_H_ */ 25 | -------------------------------------------------------------------------------- /BitArrayOperations.cpp: -------------------------------------------------------------------------------- 1 | #include "BitArrayOperations.h" 2 | 3 | void setBit(unsigned int & bitArray, unsigned char bitIndex, bool value) { 4 | if (value) { 5 | bitArray = bitArray | (1 << bitIndex); 6 | } else { 7 | bitArray = bitArray & ~(1 << bitIndex); 8 | } 9 | } 10 | 11 | void setBit(unsigned char & bitArray, unsigned char bitIndex, bool value) { 12 | if (value) { 13 | bitArray = bitArray | (1 << bitIndex); 14 | } else { 15 | bitArray = bitArray & ~(1 << bitIndex); 16 | } 17 | } 18 | 19 | bool getBit(unsigned char bitArray, unsigned char bitIndex) { 20 | return (bitArray & (1 << bitIndex)) != 0; 21 | } 22 | -------------------------------------------------------------------------------- /LEDRadioButtons.cpp: -------------------------------------------------------------------------------- 1 | #include "LEDRadioButtons.h" 2 | 3 | void LEDRadioButtons::init( unsigned char * buttonIndexes, unsigned char count) { 4 | RadioButtons::init(buttonIndexes, count); 5 | } 6 | 7 | void LEDRadioButtons::setSelectedButton(unsigned char selectedButton) { 8 | RadioButtons::setSelectedButton(selectedButton); 9 | LEDsAndButtonsHWWrapper::setLED(buttonIndexes_[selectedButton_], ILEDHW::ON); 10 | } 11 | 12 | void LEDRadioButtons::resetSelection() { 13 | if (buttonSelected_) { 14 | LEDsAndButtonsHWWrapper::setLED(buttonIndexes_[selectedButton_], ILEDHW::OFF); 15 | } 16 | RadioButtons::resetSelection(); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /LEDsAndButtonsHWWrapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LEDsAndButtonsHWWrapper.h 3 | * 4 | * Created on: 10 Oct 2017 5 | * Author: Martin Baar 6 | */ 7 | 8 | #ifndef LEDSANDBUTTONSHWWRAPPER_H_ 9 | #define LEDSANDBUTTONSHWWRAPPER_H_ 10 | 11 | #include "ILEDsAndButtonsHW.h" 12 | 13 | class LEDsAndButtonsHWWrapper { 14 | public: 15 | static ILEDsAndButtonsHW * hw_; 16 | 17 | static void setLED(unsigned char ledIndex, ILEDHW::LedState state) { 18 | hw_->setLED(ledIndex, state); 19 | } 20 | 21 | static bool isButtonDown(unsigned char index) { 22 | return hw_->isButtonDown(index); 23 | } 24 | }; 25 | 26 | #endif /* LEDSANDBUTTONSHWWRAPPER_H_ */ 27 | -------------------------------------------------------------------------------- /basic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * basic.h 3 | * 4 | * Created on: 04.02.2015 5 | * Author: user 6 | */ 7 | 8 | #ifndef BASIC_H_ 9 | #define BASIC_H_ 10 | #ifndef Arduino_h // this is not compatible with Arduino.h because macro names are identical 11 | #define Arduino_h 12 | 13 | // some basic stuff that used to reside in Arduino.h 14 | // this has been moved to a separate file to remove dependency on Arduino.h where possible 15 | 16 | 17 | #include 18 | 19 | 20 | #define min(a,b) ((a)<(b)?(a):(b)) 21 | #define max(a,b) ((a)>(b)?(a):(b)) 22 | #define abs(x) ((x)>0?(x):-(x)) 23 | 24 | #endif /* Arduino_h */ 25 | #endif /* BASIC_H_ */ 26 | -------------------------------------------------------------------------------- /random.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * random.cpp 3 | * 4 | * Created on: 10.11.2014 5 | * Author: user 6 | */ 7 | 8 | 9 | #include "random.h" 10 | #include "basic.h" 11 | 12 | 13 | 14 | uint8_t bastlRandom::byte() { 15 | static uint16_t rand_seed = 42; 16 | 17 | rand_seed ^= rand_seed << 7; 18 | rand_seed ^= rand_seed >> 11; 19 | rand_seed ^= rand_seed << 2; 20 | 21 | return rand_seed >> 8; 22 | } 23 | 24 | 25 | // works only for max-min <= 254 26 | // not equally distribiuted! 27 | uint8_t bastlRandom::range(uint8_t min, uint8_t max) { 28 | uint16_t numbChoices = max-min+1; 29 | return ((min(byte(),254)*numbChoices)>>8) + min; 30 | } 31 | -------------------------------------------------------------------------------- /RackInstrumentDefinitions.h: -------------------------------------------------------------------------------- 1 | #ifndef INSTRUMENTDEFINITIONS_H 2 | #define INSTRUMENTDEFINITIONS_H 3 | 4 | 5 | #define STEPS_PER_PATTERN 64 6 | 7 | #define DRUM_INSTRUMENTS 6 8 | #define DRUM_PATTERNS 1 9 | #define DRUM_STEPS DRUM_INSTRUMENTS * DRUM_PATTERNS * STEPS_PER_PATTERN 10 | #define DRUM_BITS_PER_STEP 6 11 | #define DRUM_BYTES (DRUM_STEPS * DRUM_BITS_PER_STEP) / 8 12 | 13 | #define MONO_INSTRUMENTS 0 14 | #define MONO_PATTERNS 0 15 | #define MONO_STEPS MONO_INSTRUMENTS * MONO_PATTERNS * STEPS_PER_PATTERN 16 | 17 | #define INSTRUMENTS DRUM_INSTRUMENTS + MONO_INSTRUMENTS 18 | 19 | #define ALL_INSTRUMENTS_IN_BYTES 3 20 | 21 | #endif // INSTRUMENTDEFINITIONS_H 22 | -------------------------------------------------------------------------------- /LFOSimple.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LFOSimple.h 3 | * 4 | * Created on: 07.04.2015 5 | * Author: user 6 | */ 7 | 8 | #ifndef LFOSIMPLE_H_ 9 | #define LFOSIMPLE_H_ 10 | 11 | #include "LFO.h" 12 | 13 | class LFOSimple : public LFO { 14 | public: 15 | 16 | LFOSimple() : waveform(SAW) { 17 | setNumbStepsToSkip(0); 18 | } 19 | virtual ~LFOSimple() {}; 20 | 21 | enum Waveform {SAW,TRIANGLE}; 22 | void setWaveform(Waveform); 23 | 24 | void setNumbStepsToSkip(uint8_t stepsToSkip); 25 | 26 | virtual uint8_t calcOutput(); 27 | 28 | private: 29 | 30 | Waveform waveform; 31 | 32 | uint16_t lastUnskippedPhase; 33 | uint16_t numbPhaseStepsToSkip; 34 | }; 35 | 36 | 37 | 38 | #endif /* LFOSIMPLE_H_ */ 39 | -------------------------------------------------------------------------------- /runAllTests.sh: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | echo -e "----------------------------------------------------------------\n" 3 | echo -e "-------------------------- NEXT TEST ---------------------------\n" 4 | echo -e "----------------------------------------------------------------\n" 5 | echo -e "\n\t===== Testing Data layer =====\n" 6 | make clean -C data/test 7 | make test -C data/test 8 | echo -e "\n\t ===== Testing Devices layer =====\n" 9 | make clean -C players/test 10 | make test -C players/test 11 | echo -e "\n\t ===== Testing Controls layer =====\n" 12 | make clean -C controls/test 13 | make test -C controls/test 14 | echo -e "\n\t ===== Testing Module layer =====\n" 15 | make clean -C modules/test 16 | make test -C modules/test 17 | -------------------------------------------------------------------------------- /spiShared.h: -------------------------------------------------------------------------------- 1 | /* 2 | * spiShared.h 3 | * 4 | * Created on: 05.08.2014 5 | * Author: user 6 | */ 7 | 8 | #ifndef SPISHARED_H_ 9 | #define SPISHARED_H_ 10 | 11 | 12 | 13 | #include 14 | #include "portManipulations.h" 15 | 16 | // SPI Pins 17 | #define SCK B,5 18 | #define MISO B,4 19 | #define MOSI B,3 20 | #define SS B,2 21 | 22 | 23 | static inline __attribute__((always_inline)) byte spiRead() { 24 | SPDR = 0xFF; // start SPI clock 25 | while (!(SPSR & _BV(SPIF))); 26 | return SPDR; 27 | } 28 | 29 | static inline __attribute__((always_inline)) byte spiWrite(byte data) { 30 | SPDR = data; 31 | while (!(SPSR & _BV(SPIF))); 32 | return SPDR; 33 | } 34 | 35 | 36 | #endif /* SPISHARED_H_ */ 37 | -------------------------------------------------------------------------------- /RadioButtons.h: -------------------------------------------------------------------------------- 1 | #ifndef RADIOBUTTONS_H 2 | #define RADIOBUTTONS_H 3 | 4 | #include "LEDsAndButtonsHWWrapper.h" 5 | 6 | class RadioButtons 7 | { 8 | public: 9 | virtual void init(unsigned char * buttonIndexes, unsigned char count); 10 | bool getSelectedButton(unsigned char & selectedButton); 11 | virtual void setSelectedButton(unsigned char selectedButton); 12 | void update(); 13 | virtual void resetSelection(); 14 | 15 | protected: 16 | unsigned char * buttonIndexes_; 17 | unsigned char buttonCount_; 18 | unsigned char selectedButton_; 19 | unsigned char lastDownButton_; 20 | bool buttonSelected_; 21 | }; 22 | 23 | inline void RadioButtons::resetSelection() { 24 | buttonSelected_ = false; 25 | } 26 | 27 | #endif // RADIOBUTTONS_H 28 | -------------------------------------------------------------------------------- /BPMConverter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BPMConverter.cpp 3 | * 4 | * Created on: Sep 12, 2014 5 | * Author: bastl 6 | */ 7 | 8 | #include "BPMConverter.h" 9 | 10 | uint16_t BPMConverter::bpmToTimeUnits(uint16_t bpm, uint16_t timeUnitsPerSecond, uint16_t sourceLeftOvers, uint16_t & leftOvers) { 11 | uint16_t base = (timeUnitsPerSecond * 60) + ((sourceLeftOvers * 60) / 1000); 12 | uint16_t division = (bpm * 16); 13 | uint32_t returnValue = base / division; 14 | uint32_t rest = (((uint32_t)base % (uint32_t)division) * 1000UL); 15 | leftOvers = (uint16_t)(rest / (uint32_t)division); 16 | return returnValue; 17 | } 18 | 19 | uint16_t BPMConverter::timeUnitsToBPM(uint16_t timeUnitsPerBeat, uint16_t timeUnitsPerSecond) { 20 | return (timeUnitsPerSecond * 60) / timeUnitsPerBeat / 16; 21 | } 22 | -------------------------------------------------------------------------------- /BitArrayOperations.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BitArrayOperations.h 3 | * 4 | * Created on: Sep 3, 2014 5 | * Author: bastl 6 | */ 7 | 8 | #ifndef BITARRAYOPERATIONS_H_ 9 | #define BITARRAYOPERATIONS_H_ 10 | 11 | 12 | #define GETBIT(X, Y) (((X) & (1 << (Y))) != 0) 13 | #define SETBITTRUE(X, Y) ((X) = ((X) | (1 << (Y)))) 14 | #define SETBITFALSE(X, Y) ((X) = ((X) & ~(1 << (Y)))) 15 | #define SETBIT(X, Y, Z) (Z ? ((X) = ((X) | (1 << (Y)))) : ((X) = ((X) & ~(1 << (Y))))) 16 | 17 | //namespace BitArrayOperations { 18 | 19 | void setBit(unsigned int & bitArray, unsigned char bitIndex, bool value); 20 | void setBit(unsigned char & bitArray, unsigned char bitIndex, bool value); 21 | bool getBit(unsigned char bitArray, unsigned char bitIndex); 22 | //} 23 | 24 | #endif /* BITARRAYOPERATIONS_H_ */ 25 | -------------------------------------------------------------------------------- /simpleSerialProtocol.h: -------------------------------------------------------------------------------- 1 | /* 2 | * simpleSerialProtocol.h 3 | * 4 | * Created on: Jan 23, 2015 5 | * Author: dasvaclav 6 | */ 7 | 8 | #ifndef SIMPLESERIALPROTOCOL_H_ 9 | #define SIMPLESERIALPROTOCOL_H_ 10 | #include 11 | #include 12 | 13 | class simpleSerialProtocol { 14 | 15 | public: 16 | void init(uint16_t baudrate); 17 | void transferMessage(uint8_t _type,uint8_t _value); 18 | // void decodeMessage(); 19 | bool recieveMessage(); 20 | uint8_t getMessageType(); 21 | uint8_t getMessageValue(); 22 | void sync(); 23 | void pairMessage(); 24 | void sendPairMessage(); 25 | //handshake if necessary 26 | 27 | private: 28 | uint8_t type; 29 | uint8_t value; 30 | uint8_t count; 31 | 32 | }; 33 | 34 | 35 | 36 | #endif /* SIMPLESERIALPROTOCOL_H_ */ 37 | -------------------------------------------------------------------------------- /LFORandom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LFORandom.h 3 | * 4 | * Created on: 07.04.2015 5 | * Author: user 6 | */ 7 | 8 | #ifndef LFORANDOM_H_ 9 | #define LFORANDOM_H_ 10 | 11 | #include "LFO.h" 12 | #include "movingAverage.h" 13 | #include "FiFoBuffer.h" 14 | 15 | class LFORandom : public LFO { 16 | public: 17 | LFORandom() : bufferPos(0), smoothness(0) {}; 18 | virtual ~LFORandom() {} 19 | 20 | void setSmoothness(uint8_t val); 21 | 22 | virtual void step(); 23 | virtual uint8_t calcOutput(); 24 | 25 | private: 26 | 27 | uint16_t thisStepDetailed; 28 | 29 | void addToBuffer(uint16_t val); 30 | uint16_t getBufferAverage(); 31 | static const uint8_t bufferSize = 32; 32 | uint16_t buffer[bufferSize]; 33 | uint8_t bufferPos; 34 | 35 | uint8_t smoothness; 36 | 37 | 38 | }; 39 | 40 | 41 | 42 | #endif /* LFORANDOM_H_ */ 43 | -------------------------------------------------------------------------------- /MIDIStepper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MIDIStepper.h 3 | * 4 | * Created on: Jul 16, 2014 5 | * Author: Martin Baar 6 | */ 7 | 8 | #ifndef MIDISTEPPER_H_ 9 | #define MIDISTEPPER_H_ 10 | 11 | #include "BastlMetronome.h" 12 | #include "IHWLayer.h" 13 | 14 | /** 15 | * Class for stepping using midi clock as an input. To be able to do this with our device we need to double the stepping 16 | * That goes from MIDI clock input. 17 | * 18 | * !!! This class makes setBPM method unusable since it is driven by MIDI clock 19 | */ 20 | class MIDIStepper : public BastlMetronome { 21 | public: 22 | MIDIStepper(); 23 | void stepMIDI(); 24 | protected: 25 | virtual unsigned char getBastlCyclesPerStep(); 26 | private: 27 | unsigned int lastMidiStepCycles_; 28 | unsigned int nextMidiStepCycles_; 29 | }; 30 | 31 | #endif /* MIDISTEPPER_H_ */ 32 | -------------------------------------------------------------------------------- /MIDIStepper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIDIStepper.cpp 3 | * 4 | * Created on: Jul 16, 2014 5 | * Author: bastl 6 | */ 7 | 8 | //#define DEBUG 9 | #ifdef DEBUG 10 | 11 | #include 12 | 13 | #endif 14 | 15 | #include "MIDIStepper.h" 16 | 17 | MIDIStepper::MIDIStepper() : BastlMetronome() { 18 | 19 | } 20 | 21 | unsigned char MIDIStepper::getBastlCyclesPerStep() { 22 | return nextMidiStepCycles_; 23 | } 24 | 25 | void MIDIStepper::stepMIDI() { 26 | 27 | /*int currentCycles = hwLayer_->getElapsedBastlCycles(); 28 | nextMidiStepCycles_ = (currentCycles - lastMidiStepCycles_) / 2; 29 | #ifdef DEBUG 30 | printf("\tCurrentCycles %d LastCycles %d NextMidiCycles %d\n",currentCycles, lastMidiStepCycles_, nextMidiStepCycles_); 31 | #endif 32 | lastMidiStepCycles_ = currentCycles; 33 | sync(); 34 | start(); 35 | stopAfterNextStep();*/ 36 | } 37 | 38 | -------------------------------------------------------------------------------- /.settings/de.innot.avreclipse.core.prefs: -------------------------------------------------------------------------------- 1 | avrtarget/ClockFrequency=16000000 2 | avrtarget/ExtRAMSize=0 3 | avrtarget/ExtendedRAM=false 4 | avrtarget/MCUType=atmega328p 5 | avrtarget/UseEEPROM=false 6 | avrtarget/UseExtendedRAMforHeap=true 7 | avrtarget/avrdude/BitBangDelay= 8 | avrtarget/avrdude/Bitclock= 9 | avrtarget/avrdude/EEPROMFile= 10 | avrtarget/avrdude/EEPROMFromConfig=true 11 | avrtarget/avrdude/FlashFile= 12 | avrtarget/avrdude/FlashFromConfig=true 13 | avrtarget/avrdude/NoChipErase=false 14 | avrtarget/avrdude/NoSigCheck=false 15 | avrtarget/avrdude/NoVerify=false 16 | avrtarget/avrdude/NoWrite=false 17 | avrtarget/avrdude/OtherOptions= 18 | avrtarget/avrdude/ProgrammerID=programmerconfig.1 19 | avrtarget/avrdude/UseCounter=false 20 | avrtarget/avrdude/WriteEEPROM=false 21 | avrtarget/avrdude/WriteFlash=true 22 | avrtarget/perConfig=false 23 | eclipse.preferences.version=1 24 | -------------------------------------------------------------------------------- /modules/test/Makefile: -------------------------------------------------------------------------------- 1 | CPP_FILES_CLASS = $(wildcard` ../*.cpp) 2 | OBJ_FILES_CLASS = $(addprefix ../obj/,$(notdir $(CPP_FILES:.cpp=.o))) 3 | #CPP_FILES = tst.cpp 4 | OBJ_FILES = tst_step.o 5 | LD_FLAGS= 6 | CC_FLAGS=-c -Wall -fno-strict-overflow 7 | 8 | #test: $(OBJ_FILES) $(OBJ_FILES_CLASS) 9 | # g++ $(LD_FLAGS) -o $@ $^ 10 | 11 | test : tst.o SteppingHWLayerMock.o ../Stepper.o ../MIDIStepper.o 12 | g++ -o $@ $^ 13 | ./test 14 | 15 | tst.o : tst.cpp 16 | g++ $(CC_FLAGS) -o $@ $< 17 | 18 | SteppingHWLayerMock.o : SteppingHWLayerMock.cpp 19 | g++ $(CC_FLAGS) -o $@ $< 20 | 21 | ../Stepper.o : ../Stepper.cpp 22 | g++ $(CC_FLAGS) -o $@ $< 23 | 24 | ../MIDIStepper.o : ../MIDIStepper.cpp 25 | g++ $(CC_FLAGS) -o $@ $< 26 | 27 | #../obj/%.o: ../%.cpp 28 | # g++ -I../ -c -o $@ $< 29 | # 30 | #%.o : %.cpp 31 | # g++ -I../ -c -o $@ $< -I../ISequenceMemory.h 32 | 33 | clean: 34 | rm ../*.o 35 | rm *.o 36 | rm test 37 | 38 | -------------------------------------------------------------------------------- /data/test/SRAMHWMock.h: -------------------------------------------------------------------------------- 1 | #ifndef SRAMHWMOCK_H 2 | #define SRAMHWMOCK_H 3 | 4 | #include "../../hw/IHWLayer.h" 5 | 6 | class SRAMHWMock : public IHWLayer 7 | { 8 | public: 9 | SRAMHWMock(); 10 | virtual IHWLayer::ButtonState getButtonState(unsigned char index); 11 | virtual void setLED(unsigned char index, IHWLayer::LedState state); 12 | virtual unsigned char getKnobValue(unsigned char index); 13 | virtual unsigned char readSRAM(long address); 14 | virtual void readSRAM(long address, unsigned char * data, unsigned int size); 15 | virtual void writeSRAM(long address, unsigned char data); 16 | virtual void writeSRAM(long address, unsigned char * data, unsigned int size); 17 | virtual unsigned int getElapsedBastlCycles() {return 0;}; 18 | virtual unsigned int getBastlCyclesPerSecond() {return 0;}; 19 | 20 | private: 21 | unsigned char data_[256000]; 22 | }; 23 | 24 | #endif // SRAMHWMOCK_H 25 | -------------------------------------------------------------------------------- /test/testMapping.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | #include "../mapping.h" 6 | 7 | 8 | 9 | 10 | 11 | int main( int argc, const char* argv[] ) { 12 | 13 | for (uint16_t index=0; index<256; index++) { 14 | printf("%u ",index); 15 | 16 | // unsigned 17 | printf("%u ",mapLinearRuntimeFastU8U16((uint8_t)index,0,-1)); 18 | printf("%u ",mapLinearRuntimePreciseU8U16((uint8_t)index,0,-1)); 19 | printf("%u ",mapLinearRuntimeFastU8U16((uint8_t)index,-1,0)); 20 | printf("%u ",mapLinearRuntimePreciseU8U16((uint8_t)index,-1,0)); 21 | 22 | // signed 23 | printf("%i ",mapLinearRuntimeFastU8S16((uint8_t)index,-30000,30000)); 24 | printf("%i ",mapLinearRuntimePreciseU8S16((uint8_t)index,-30000,30000)); 25 | printf("%i ",mapLinearRuntimeFastU8S16((uint8_t)index,30000,-30000)); 26 | printf("%i ",mapLinearRuntimePreciseU8S16((uint8_t)index,30000,-30000)); 27 | printf("\n"); 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /LFO.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LFO.h 3 | * 4 | * Created on: 07.04.2015 5 | * Author: user 6 | */ 7 | 8 | #ifndef LFO_H_ 9 | #define LFO_H_ 10 | 11 | #include 12 | 13 | 14 | class LFO { 15 | public: 16 | LFO(); 17 | virtual ~LFO(){}; 18 | void init(); 19 | void setFrequency(uint16_t bastlCyclesPerPeriod); 20 | 21 | void setToStep(uint8_t stepNumber, uint16_t timestamp); 22 | 23 | void setFlop(uint8_t bitVector); 24 | void setXOR(uint8_t bitVector); 25 | void setFolding(uint8_t thres); 26 | void setOverflow(uint8_t thres); 27 | 28 | uint8_t getValue(uint16_t timestamp); 29 | 30 | virtual void step(); 31 | virtual uint8_t calcOutput() = 0; 32 | 33 | 34 | protected: 35 | uint16_t currentPhase; 36 | uint8_t currentStep; 37 | uint16_t phaseIncrement; 38 | 39 | uint16_t lastTimestamp; 40 | 41 | uint8_t flopVector; 42 | uint8_t xorVector; 43 | uint8_t thres; 44 | bool isFolding; 45 | 46 | uint8_t currentOutput; 47 | 48 | }; 49 | 50 | 51 | 52 | 53 | #endif /* LFO_H_ */ 54 | -------------------------------------------------------------------------------- /ArduinoMIDICommandProcessor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ArduinoMIDICommandProcessor.h 3 | * 4 | * Created on: Jul 17, 2014 5 | * Author: Martin Baar 6 | */ 7 | 8 | #include "IMIDICommandProcessor.h" 9 | 10 | #ifndef ARDUINOMIDICOMMANDPROCESSOR_H_ 11 | #define ARDUINOMIDICOMMANDPROCESSOR_H_ 12 | 13 | class ArduinoMIDICommandProcessor : public IMIDICommandProcessor { 14 | public: 15 | ArduinoMIDICommandProcessor(void (*sendNoteOnCallback)(unsigned char note, 16 | unsigned char velocity, 17 | unsigned char channel), 18 | void (*sendNoteOffCallback)(unsigned char note, 19 | unsigned char velocity, 20 | unsigned char channel)); 21 | virtual void SendCommand(MIDICommand & command); 22 | private: 23 | void (*sendNoteOnCallback_)(unsigned char note, unsigned char velocity, unsigned char channel); 24 | void (*sendNoteOffCallback_)(unsigned char note, unsigned char velocity, unsigned char channel); 25 | }; 26 | 27 | #endif /* ARDUINOMIDICOMMANDPROCESSOR_H_ */ 28 | -------------------------------------------------------------------------------- /data/test/Makefile: -------------------------------------------------------------------------------- 1 | CPP_FILES_CLASS = $(wildcard` ../*.cpp) 2 | OBJ_FILES_CLASS = $(addprefix ../obj/,$(notdir $(CPP_FILES:.cpp=.o))) 3 | #CPP_FILES = tst.cpp 4 | OBJ_FILES = tst_step.o 5 | LD_FLAGS= 6 | CC_FLAGS=-c -Wall 7 | 8 | #test: $(OBJ_FILES) $(OBJ_FILES_CLASS) 9 | # g++ $(LD_FLAGS) -o $@ $^ 10 | 11 | test : tst.o SRAMHWMock.o ../Step.o ../DrumStep.o DummyStepMemory.o ../FlashStepMemory.o 12 | g++ -o $@ $^ 13 | ./test 14 | 15 | SRAMHWMock.o : SRAMHWMock.cpp 16 | g++ $(CC_FLAGS) -o $@ $< 17 | 18 | tst_step.o : tst_step.cpp 19 | g++ $(CC_FLAGS) -o $@ $< 20 | 21 | ../Step.o : ../Step.cpp 22 | g++ $(CC_FLAGS) -o $@ $< 23 | 24 | ../DrumStep.o : ../DrumStep.cpp 25 | g++ $(CC_FLAGS) -o $@ $< 26 | 27 | DummyStepMemory.o : DummyStepMemory.cpp 28 | g++ $(CC_FLAGS) -o $@ $< 29 | 30 | ../FlashStepMemory.o : ../FlashStepMemory.cpp 31 | g++ $(CC_FLAGS) -o $@ $< 32 | 33 | 34 | #../obj/%.o: ../%.cpp 35 | # g++ -I../ -c -o $@ $< 36 | # 37 | #%.o : %.cpp 38 | # g++ -I../ -c -o $@ $< -I../ISequenceMemory.h 39 | 40 | clean: 41 | rm ../*.o 42 | rm *.o 43 | rm test 44 | 45 | -------------------------------------------------------------------------------- /data/test/DummyStepMemory.h: -------------------------------------------------------------------------------- 1 | #ifndef DUMMYSEQUENCEMEMORY_H 2 | #define DUMMYSEQUENCEMEMORY_H 3 | 4 | #include "../IStepMemory.h" 5 | #include "../InstrumentDefinitions.h" 6 | 7 | class DummyStepMemory : public IStepMemory 8 | { 9 | public: 10 | 11 | DummyStepMemory(); 12 | virtual DrumStep getDrumStep(unsigned char instrumentID, unsigned char pattern, unsigned char step); 13 | virtual bool setDrumStep(unsigned char instrumentID, unsigned char pattern, unsigned char step, DrumStep stepData); 14 | virtual bool getNextActiveDrumStep(unsigned char instrumentID, unsigned char pattern, unsigned char & step, DrumStep & drumStep) ; 15 | virtual void getActivesAndMutesForNote(unsigned char instrumentID, unsigned char pattern, unsigned char windowIndex, unsigned char * data){}; 16 | virtual void getPatternSettings(unsigned char patternIndex, unsigned char * settings){}; 17 | virtual void setPatternSettings(unsigned char patternIndex, unsigned char * settings){}; 18 | private: 19 | DrumStep drumSteps_[DRUM_STEPS]; 20 | }; 21 | 22 | #endif // DUMMYSEQUENCEMEMORY_H 23 | -------------------------------------------------------------------------------- /StepSynchronizer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * StepSynchronizer.h 3 | * 4 | * Created on: Sep 12, 2014 5 | * Author: bastl 6 | */ 7 | 8 | #ifndef STEPSYNCHRONIZER_H_ 9 | #define STEPSYNCHRONIZER_H_ 10 | 11 | class StepSynchronizer { 12 | public: 13 | StepSynchronizer(); 14 | void setCycleLength(unsigned int cycleLength); 15 | void doStep(); 16 | void reset(); 17 | unsigned char getCurrentStepNumber(); 18 | private: 19 | unsigned int cycleLength_; 20 | unsigned char currentStepNumber_; 21 | bool waiting_; 22 | }; 23 | 24 | inline void StepSynchronizer::setCycleLength(unsigned int cycleLength) { 25 | cycleLength_ = cycleLength; 26 | } 27 | 28 | inline void StepSynchronizer::doStep() { 29 | if (waiting_) { 30 | waiting_ = false; 31 | } else { 32 | currentStepNumber_ = (currentStepNumber_ + 1) % cycleLength_; 33 | } 34 | } 35 | 36 | inline unsigned char StepSynchronizer::getCurrentStepNumber() { 37 | return currentStepNumber_; 38 | } 39 | 40 | inline void StepSynchronizer::reset() { 41 | currentStepNumber_ = 0; 42 | waiting_ = true; 43 | } 44 | 45 | #endif /* STEPSYNCHRONIZER_H_ */ 46 | -------------------------------------------------------------------------------- /fastAnalogRead.h: -------------------------------------------------------------------------------- 1 | /* 2 | * fastAnalogRead.h 3 | * 4 | * Created on: 22.09.2014 5 | * Author: user 6 | */ 7 | 8 | #ifndef FASTANALOGREAD_H_ 9 | #define FASTANALOGREAD_H_ 10 | 11 | #include 12 | #include 13 | 14 | namespace fastAnalogRead { 15 | 16 | void init() { 17 | ADMUX = (1< 2 | #include 3 | #include "../FiFoBuffer.h" 4 | 5 | const uint8_t size = 3; 6 | 7 | FiFoBuffer buffer(99); 8 | 9 | int main( int argc, const char* argv[] ) { 10 | 11 | printf("FillCount: %u\n",buffer.getfillCount()); 12 | printf("Empty: %u\n",buffer.isEmpty()); 13 | printf("Full: %u\n\n", buffer.isFull()); 14 | 15 | for (uint8_t index=0; index 6 | #define BUFFER_SIZE 64 7 | class MIDInoteBuffer { 8 | 9 | public: 10 | void init(); 11 | void addNoteToBuffer(uint8_t _note, uint8_t _velocity); 12 | bool removeNoteFromBuffer(uint8_t note); 13 | void orderBuffer(); 14 | void setPolyphony(uint8_t _polyphony); 15 | uint8_t getNoteForVoice(uint8_t _voice); 16 | 17 | uint8_t getNoteToBePlayedAgain(); 18 | uint8_t getVelocityOfNoteToBePlayedAgain(); 19 | uint8_t getNumberOfNotesInBuffer(); 20 | uint8_t getNoteFromBuffer(uint8_t _note); 21 | uint8_t getVelocityFromBuffer(uint8_t _note); 22 | uint8_t getNoteFromOrderedBuffer(uint8_t _note); 23 | 24 | // 25 | void clearBuffers(); 26 | 27 | 28 | 29 | private: 30 | uint8_t polyphony; 31 | uint8_t notesInBuffer; 32 | uint8_t midiBuffer[BUFFER_SIZE]; 33 | uint8_t velocityBuffer[BUFFER_SIZE]; 34 | uint8_t orderedBuffer[BUFFER_SIZE]; 35 | void shiftBuffer(uint8_t direction,uint8_t from); 36 | uint8_t findNoteInBuffer(uint8_t note); 37 | 38 | }; 39 | 40 | 41 | 42 | 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /ArduinoMIDICommandProcessor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ArduinoMIDICommandProcessor.cpp 3 | * 4 | * Created on: Jul 17, 2014 5 | * Author: Martin Baar 6 | */ 7 | 8 | #include "ArduinoMIDICommandProcessor.h" 9 | 10 | ArduinoMIDICommandProcessor::ArduinoMIDICommandProcessor(void (*sendNoteOnCallback)(unsigned char note, 11 | unsigned char velocity, 12 | unsigned char channel), 13 | void (*sendNoteOffCallback)(unsigned char note, 14 | unsigned char velocity, 15 | unsigned char channel)) : 16 | sendNoteOnCallback_(sendNoteOnCallback), 17 | sendNoteOffCallback_(sendNoteOffCallback){ 18 | } 19 | 20 | void ArduinoMIDICommandProcessor::SendCommand(MIDICommand & command) { 21 | if (command.getType() == MIDICommand::NOTEON) { 22 | if (sendNoteOnCallback_ != 0) { 23 | sendNoteOnCallback_(command.getNote(), command.getVelocity(), command.getChannel()); 24 | } 25 | } else { 26 | if (sendNoteOffCallback_ != 0) { 27 | sendNoteOffCallback_(command.getNote(), command.getVelocity(), command.getChannel()); 28 | } 29 | } 30 | 31 | } 32 | 33 | -------------------------------------------------------------------------------- /data/test/SRAMHWMock.cpp: -------------------------------------------------------------------------------- 1 | #include "SRAMHWMock.h" 2 | 3 | SRAMHWMock::SRAMHWMock() 4 | { 5 | for (long i = 0; i < 256000; i++) { 6 | data_[i] = 255; 7 | } 8 | } 9 | 10 | IHWLayer::ButtonState SRAMHWMock::getButtonState(unsigned char index) 11 | { 12 | return IHWLayer::UP; 13 | } 14 | 15 | void SRAMHWMock::setLED(unsigned char index, IHWLayer::LedState state) 16 | { 17 | 18 | } 19 | 20 | unsigned char SRAMHWMock::getKnobValue(unsigned char index) 21 | { 22 | return 0; 23 | } 24 | 25 | unsigned char SRAMHWMock::readSRAM(long address) 26 | { 27 | return data_[address]; 28 | } 29 | 30 | void SRAMHWMock::readSRAM(long address, unsigned char *data, unsigned int size) 31 | { 32 | for (unsigned char i = 0; i < size; i++) { 33 | data[i] = data_[i + address]; 34 | } 35 | } 36 | 37 | void SRAMHWMock::writeSRAM(long address, unsigned char data) 38 | { 39 | data_[address] = data; 40 | } 41 | 42 | void SRAMHWMock::writeSRAM(long address, unsigned char *data, unsigned int size) 43 | { 44 | for (unsigned char i = 0; i < size; i++) { 45 | data_[i + address] = data[i]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /players/test/MIDICommandProcessorMock.h: -------------------------------------------------------------------------------- 1 | #ifndef MIDICOMMANDPROCESSORMOCK_H 2 | #define MIDICOMMANDPROCESSORMOCK_H 3 | 4 | #include "../IMIDICommandProcessor.h" 5 | 6 | class MIDICommandProcessorMock : public IMIDICommandProcessor 7 | { 8 | public: 9 | MIDICommandProcessorMock(); 10 | virtual void SendCommand(MIDICommand & command); 11 | void clear(); 12 | unsigned char getNoteOffCountForChannel(unsigned char channel); 13 | unsigned char getNoteOnCountForChannel(unsigned char channel); 14 | private: 15 | unsigned char noteOnCount_[16]; 16 | unsigned char noteOffCount_[16]; 17 | }; 18 | 19 | inline unsigned char MIDICommandProcessorMock::getNoteOffCountForChannel(unsigned char channel) { 20 | return noteOffCount_[channel]; 21 | } 22 | 23 | inline unsigned char MIDICommandProcessorMock::getNoteOnCountForChannel(unsigned char channel) { 24 | return noteOnCount_[channel]; 25 | } 26 | 27 | inline void MIDICommandProcessorMock::clear() { 28 | for (unsigned char i = 0; i < 16; i++) { 29 | noteOffCount_[i] = 0; 30 | noteOnCount_[i] = 0; 31 | } 32 | } 33 | 34 | #endif // MIDICOMMANDPROCESSORMOCK_H 35 | -------------------------------------------------------------------------------- /modules/test/SteppingHWLayerMock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SteppingHWLayerMock.h 3 | * 4 | * Created on: Jul 16, 2014 5 | * Author: bastl 6 | */ 7 | 8 | #ifndef STEPPINGHWLAYERMOCK_H_ 9 | #define STEPPINGHWLAYERMOCK_H_ 10 | 11 | #include "../../hw/IHWLayer.h" 12 | 13 | class SteppingHWLayerMock : public IHWLayer{ 14 | public: 15 | virtual ButtonState getButtonState(unsigned char index) {return IHWLayer::UP;} 16 | virtual void setLED(unsigned char index, LedState state) {} 17 | virtual unsigned char getKnobValue(unsigned char index) {return 0;} 18 | virtual unsigned char readSRAM(long address) {return 0;} 19 | virtual void readSRAM(long address, unsigned char * data, unsigned int size) {} 20 | virtual void writeSRAM(long address, unsigned char data) {} 21 | virtual void writeSRAM(long address, unsigned char * data, unsigned int size) {} 22 | virtual unsigned int getElapsedBastlCycles() {return elapsedBastlCycles_;} 23 | virtual unsigned int getBastlCyclesPerSecond() {return bastlCyclesPerSecond_;} 24 | void setBastlCyclesPerSecond(unsigned int bastlCyclesPerSecond); 25 | void setElapsedBastlCycles(unsigned int elapsedBastlCycles); 26 | private: 27 | unsigned int bastlCyclesPerSecond_; 28 | unsigned int elapsedBastlCycles_; 29 | }; 30 | 31 | #endif /* STEPPINGHWLAYERMOCK_H_ */ 32 | -------------------------------------------------------------------------------- /IStepMemory.h: -------------------------------------------------------------------------------- 1 | #ifndef ISEQUENCEMEMORY_H 2 | #define ISEQUENCEMEMORY_H 3 | 4 | #include "DrumStep.h" 5 | 6 | class IStepMemory 7 | { 8 | public: 9 | enum ActiveMultiStatus{ALLACTIVE, ALLINACTIVE, MIXED}; 10 | virtual DrumStep getDrumStep( unsigned char instrumentID, unsigned char step) = 0; 11 | virtual unsigned char getNumberOfActives(unsigned char instrumentID); 12 | virtual bool getNextActiveDrumStep( unsigned char instrumentID, unsigned char & step, DrumStep & drumStep) = 0; 13 | virtual bool setDrumStep( unsigned char instrumentID, unsigned char step, DrumStep stepData) = 0; 14 | virtual void setDataReference(unsigned char * dataReference) = 0; 15 | virtual unsigned char * getDataReference() = 0; 16 | virtual void getAllInstrumentActivesFor16Steps(unsigned char fromIndex, ActiveMultiStatus * result) = 0; 17 | virtual void makeActiveUpTo(unsigned char instrument, unsigned char indexUpTo) = 0; 18 | virtual void makeAllInstrumentsActiveUpTo(unsigned char indexUpTo) = 0; 19 | virtual void clearStepsForInstrument(unsigned char instrument) = 0; 20 | virtual void clearStepsForAllInstruments() = 0; 21 | virtual void getMutesForNote(unsigned char instrumentID, unsigned char windowIndex, unsigned char *& data) = 0; 22 | 23 | }; 24 | 25 | 26 | #endif // ISEQUENCEMEMORY_H 27 | -------------------------------------------------------------------------------- /LFO.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * LFO.cpp 3 | * 4 | * Created on: 07.04.2015 5 | * Author: user 6 | */ 7 | 8 | 9 | #include "LFO.h" 10 | 11 | 12 | LFO::LFO() :currentPhase(0), lastTimestamp(0), flopVector(0), xorVector(0), thres(255) 13 | { 14 | } 15 | 16 | 17 | void LFO::setFrequency(uint16_t bastlCyclesPerPeriod) { 18 | 19 | if (bastlCyclesPerPeriod == 0) { 20 | phaseIncrement = 0; 21 | return; 22 | } 23 | 24 | phaseIncrement = ((uint32_t)65536 + (bastlCyclesPerPeriod>>1))/bastlCyclesPerPeriod; 25 | } 26 | 27 | 28 | void LFO::setToStep(uint8_t stepNumber, uint16_t timestamp) { 29 | lastTimestamp = timestamp; 30 | currentPhase = stepNumber << 8; 31 | } 32 | 33 | void LFO::setFlop(uint8_t bitVector) { 34 | flopVector = bitVector; 35 | } 36 | void LFO::setXOR(uint8_t bitVector) { 37 | xorVector = bitVector; 38 | } 39 | void LFO::setFolding(uint8_t thres) { 40 | this->thres = thres; 41 | isFolding = true; 42 | } 43 | void LFO::setOverflow(uint8_t thres) { 44 | this->thres = thres; 45 | isFolding = false; 46 | } 47 | 48 | 49 | void LFO::step() { 50 | currentPhase += phaseIncrement; 51 | } 52 | 53 | uint8_t LFO::getValue(uint16_t timestamp) { 54 | while(lastTimestamp != timestamp) { 55 | step(); 56 | lastTimestamp++; 57 | } 58 | currentStep = currentPhase >> 8; 59 | return calcOutput(); 60 | } 61 | 62 | 63 | -------------------------------------------------------------------------------- /test/testAverage.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | #include "../movingAverage.h" 6 | 7 | 8 | MovingAverageLinear average(4); 9 | 10 | 11 | 12 | int main( int argc, const char* argv[] ) { 13 | 14 | 15 | printf("Pulse in\n"); 16 | printf("%u\n",average.getAverage()); 17 | average.add(100); 18 | printf("%u\n",average.getAverage()); 19 | average.add(0); 20 | printf("%u\n",average.getAverage()); 21 | average.add(0); 22 | printf("%u\n",average.getAverage()); 23 | average.add(0); 24 | printf("%u\n",average.getAverage()); 25 | average.add(0); 26 | printf("%u\n",average.getAverage()); 27 | 28 | printf("\n"); 29 | printf("Add new element\n"); 30 | average.add(100); 31 | printf("%u\n",average.getAverage()); 32 | printf("Clear and add same element\n"); 33 | average.clear(); 34 | average.add(100); 35 | printf("%u\n",average.getAverage()); 36 | printf("Only clear and read\n"); 37 | average.clear(); 38 | printf("%u\n",average.getAverage()); 39 | 40 | printf("\n"); 41 | printf("Big Values\n"); 42 | average.add(2277); 43 | printf("%u\n",average.getAverage()); 44 | average.add(2521); 45 | printf("%u\n",average.getAverage()); 46 | average.add(2317); 47 | printf("%u\n",average.getAverage()); 48 | average.add(2399); 49 | printf("%u\n",average.getAverage()); 50 | 51 | 52 | 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /test/testStepper.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../Stepper.h" 6 | 7 | 8 | 9 | 10 | class RedirStdOut { 11 | public: 12 | 13 | static void setToFile(std::string filename) { 14 | 15 | static const std::string subfolder = "data"; 16 | 17 | filename = subfolder + "/" + filename; 18 | 19 | if((fp=freopen(filename.c_str(), "w" ,stdout))==NULL) { 20 | printf("Cannot open file.\n"); 21 | exit(1); 22 | } 23 | } 24 | 25 | static void setToConsole() { 26 | fclose(fp); 27 | freopen ("/dev/tty", "a", stdout); 28 | } 29 | 30 | private: 31 | static FILE *fp; 32 | 33 | }; 34 | 35 | FILE* RedirStdOut::fp; 36 | 37 | 38 | 39 | Stepper step; 40 | 41 | 42 | 43 | int main( int argc, const char* argv[] ) { 44 | 45 | printf("Starting\n"); 46 | 47 | RedirStdOut::setToFile("Stepper.csv"); 48 | 49 | uint16_t time = 0; 50 | uint8_t inc = 1; 51 | step.init(15,32,3); 52 | step.setToStep(time,0); 53 | 54 | printf("Timestamp currentStep closestStep\n"); 55 | 56 | for (uint32_t realTime=time; realTime<1000; realTime+=inc,time+=inc) { 57 | printf("%u %u %u \n",realTime,step.getCurrentStep(time), step.getClosestStep(time)); 58 | if (realTime == 300) { 59 | step.setToStep(time,0); 60 | } 61 | } 62 | 63 | printf("done\n"); 64 | 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /players/test/Makefile: -------------------------------------------------------------------------------- 1 | CPP_FILES_CLASS = $(wildcard` ../*.cpp) 2 | OBJ_FILES_CLASS = $(addprefix ../obj/,$(notdir $(CPP_FILES:.cpp=.o))) 3 | #CPP_FILES = tst.cpp 4 | OBJ_FILES = tst_step.o 5 | LD_FLAGS= 6 | CC_FLAGS=-c -Wall 7 | 8 | #test: $(OBJ_FILES) $(OBJ_FILES_CLASS) 9 | # g++ $(LD_FLAGS) -o $@ $^ 10 | 11 | test : tst.o MIDICommandProcessorMock.o ../Player.o ../PlayerSettings.o ../../data/DrumStep.o ../../data/test/DummyStepMemory.o ../../data/MIDICommand.o ../../data/Step.o 12 | g++ -o $@ $^ 13 | ./test 14 | 15 | tst.o : tst.cpp 16 | g++ $(CC_FLAGS) -o $@ $< 17 | 18 | MIDICommandProcessorMock.o : MIDICommandProcessorMock.cpp 19 | g++ $(CC_FLAGS) -o $@ $< 20 | 21 | ../Player.o : ../Player.cpp 22 | g++ $(CC_FLAGS) -o $@ $< 23 | 24 | ../PlayerSettings.o : ../PlayerSettings.cpp 25 | g++ $(CC_FLAGS) -o $@ $< 26 | 27 | ../../data/DrumStep.o : ../../data/DrumStep.cpp 28 | g++ $(CC_FLAGS) -o $@ $< 29 | 30 | ../../data/test/DummyStepMemory.o : ../../data/test/DummyStepMemory.cpp 31 | g++ $(CC_FLAGS) -o $@ $< 32 | 33 | ../../data/Step.o : ../../data/Step.cpp 34 | g++ $(CC_FLAGS) -o $@ $< 35 | 36 | ../../data/MIDICommand.o : ../../data/MIDICommand.cpp 37 | g++ $(CC_FLAGS) -o $@ $< 38 | 39 | #../obj/%.o: ../%.cpp 40 | # g++ -I../ -c -o $@ $< 41 | # 42 | #%.o : %.cpp 43 | # g++ -I../ -c -o $@ $< -I../ISequenceMemory.h 44 | 45 | clean: 46 | rm ../*.o 47 | rm *.o 48 | rm ../../data/*.o 49 | rm test 50 | 51 | -------------------------------------------------------------------------------- /simpleSerialProtocol.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * simpleSerialProtocol.cpp 3 | * 4 | * Created on: Jan 23, 2015 5 | * Author: dasvaclav 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | 12 | /* 13 | simpleSerialProtocol::simpleSerialProtocol(){ 14 | 15 | } 16 | */ 17 | void simpleSerialProtocol::init(uint16_t baudrate){ 18 | Serial.begin(baudrate); 19 | } 20 | void simpleSerialProtocol::transferMessage(uint8_t _type,uint8_t _value){ 21 | Serial.write(_type); 22 | Serial.write(_value); 23 | } 24 | #define PAIR_TYPE 9 25 | #define PAIR_VALUE 9 26 | 27 | bool simpleSerialProtocol::recieveMessage(){ 28 | if(Serial.available()){ 29 | if(count==0){ 30 | type=Serial.read(), count=1; 31 | if(type==PAIR_TYPE && value==PAIR_VALUE) sync(); //sync routine 32 | } 33 | if(count==1) { 34 | if(Serial.available()){ 35 | value=Serial.read(), count=0; 36 | if(type==PAIR_TYPE && value==PAIR_VALUE) sync(); //sync routine 37 | return true; 38 | } 39 | else{ 40 | return false; 41 | } 42 | } 43 | } 44 | else{ 45 | return false; 46 | } 47 | } 48 | uint8_t simpleSerialProtocol::getMessageType(){ 49 | return type; 50 | } 51 | uint8_t simpleSerialProtocol::getMessageValue(){ 52 | return value; 53 | } 54 | void simpleSerialProtocol::pairMessage(){ 55 | transferMessage(PAIR_TYPE,PAIR_VALUE); 56 | } 57 | 58 | void simpleSerialProtocol::sync(){ 59 | count=0; 60 | type=0; 61 | value=0; 62 | } 63 | -------------------------------------------------------------------------------- /StepRecorder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * StepRecorder.h 3 | * 4 | * Created on: Aug 28, 2014 5 | * Author: bastl 6 | */ 7 | 8 | #ifndef STEPRECORDER_H_ 9 | #define STEPRECORDER_H_ 10 | 11 | #include "Player.h" 12 | #include "PlayerSettings.h" 13 | #include "IStepMemory.h" 14 | #include 15 | 16 | class StepRecorder { 17 | public: 18 | StepRecorder(); 19 | void init(Player * player, IStepMemory * memory, PlayerSettings * playerSettings, BastlStepper * stepper); 20 | void update(); 21 | void record(bool record); 22 | unsigned int startRecordNote(unsigned char instrumentIndex); 23 | void stopRecordNote(unsigned char instrumentIndex); 24 | void recordMIDINote(unsigned char channel, unsigned char note); 25 | void setCurrentStepper(BastlStepper * stepper); 26 | private: 27 | Player * player_; 28 | IStepMemory * memory_; 29 | PlayerSettings * playerSettings_; 30 | BastlStepper * stepper_; 31 | 32 | bool record_; 33 | bool recordInstrumentStatuses_[6]; 34 | unsigned char lastQuantizedSteps_[6]; 35 | 36 | unsigned char getCurrentQuantizedSubstep(unsigned char instrumentIndex); 37 | void recordSubsteps(unsigned char instrumentIndex, unsigned char subStepStartIndex); 38 | 39 | 40 | }; 41 | 42 | inline void StepRecorder::record(bool record) { 43 | 44 | record_ = record; 45 | } 46 | 47 | inline void StepRecorder::setCurrentStepper(BastlStepper * stepper) { 48 | stepper_ = stepper; 49 | } 50 | 51 | 52 | #endif /* STEPRECORDER_H_ */ 53 | -------------------------------------------------------------------------------- /SimplifiedTapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SimplifiedTapper.h 3 | * 4 | * Created on: Sep 5, 2014 5 | * Author: bastl 6 | */ 7 | 8 | #ifndef SIMPLIFIED_TAPPER_H_ 9 | #define SIMPLIFIED_TAPPER_H_ 10 | 11 | #include "ITapper.h" 12 | 13 | class SimplifiedTapper : public ITapper { 14 | public: 15 | SimplifiedTapper(); 16 | virtual ~SimplifiedTapper(); 17 | virtual void init(unsigned int maxStepLengthInTimeUnits, unsigned int maxStepDeviationInTImeUnits); 18 | virtual void tap(unsigned int tapTime); 19 | virtual void setStepsPerTap(unsigned char stepsPerTap); 20 | virtual unsigned int getTimeUnitsPerStep(); 21 | virtual void setStepCallBack(void (*makeStep)()); 22 | virtual bool anyStepDetected(); 23 | unsigned int lastTapTime; 24 | private: 25 | char stepsInRow_; 26 | unsigned int lastTapTime_; 27 | unsigned int currentTapTime_; 28 | unsigned int stepsPerTap_; 29 | unsigned int maxStepLengthInTimeUnits_; 30 | unsigned int maxStepDeviationInTImeUnits_; 31 | 32 | void (*makeStep_)(); 33 | }; 34 | 35 | inline void SimplifiedTapper::setStepsPerTap(unsigned char stepsPerTap) { 36 | stepsPerTap_ = stepsPerTap; 37 | } 38 | 39 | inline unsigned int SimplifiedTapper::getTimeUnitsPerStep() { 40 | return currentTapTime_ / stepsPerTap_; 41 | } 42 | 43 | inline void SimplifiedTapper::setStepCallBack(void (*makeStep)()) { 44 | makeStep_ = makeStep; 45 | } 46 | 47 | inline bool SimplifiedTapper::anyStepDetected() { 48 | return stepsInRow_ > 1; 49 | } 50 | 51 | #endif /* TAPPER_H_ */ 52 | -------------------------------------------------------------------------------- /DrumStep.h: -------------------------------------------------------------------------------- 1 | #ifndef DRUMSTEP_H 2 | #define DRUMSTEP_H 3 | 4 | #include "Step.h" 5 | 6 | class DrumStep : public Step 7 | { 8 | public: 9 | enum DrumVelocityType {UP = 0, DOWN, NORMAL, OFF}; 10 | DrumStep(); 11 | /** 12 | * @brief DrumStep 13 | * @param mute 14 | * @param substeps 15 | */ 16 | DrumStep(bool mute, DrumVelocityType substeps[]); 17 | 18 | DrumVelocityType getSubStep(unsigned char index); 19 | void setSubStep(unsigned char index, DrumVelocityType type); 20 | private: 21 | DrumVelocityType _substeps[4]; 22 | }; 23 | 24 | inline DrumStep::DrumVelocityType DrumStep::getSubStep(unsigned char index) { 25 | // Be carrefull here dont ask for nonexisting substeps otherwise you get strange behaviour. 26 | // The if test has been skipped here because it has no sence in this application since we cannot 27 | // raise exception and returning default value is not correct either. If statement would at the same time 28 | // steel proccessor time that we could use for other important stuff 29 | return _substeps[index]; 30 | } 31 | 32 | inline void DrumStep::setSubStep(unsigned char index, DrumVelocityType type) { 33 | // Be carrefulk here dont set nonexisting substeps otherwise you get strange behaviour. 34 | // The if test has been skipped here because it has no sence in this application since we cannot 35 | // raise exception and returning default value is not correct either. If statement would at the same time 36 | // steel proccessor time that we could use for other important stuff 37 | _substeps[index] = type; 38 | } 39 | 40 | #endif // DRUMSTEP_H 41 | -------------------------------------------------------------------------------- /FlashStepMemory.h: -------------------------------------------------------------------------------- 1 | #ifndef FLASHSTEPMEMORY_H 2 | #define FLASHSTEPMEMORY_H 3 | 4 | #include "IHWLayer.h" 5 | #include "IStepMemory.h" 6 | #include "DrumStep.h" 7 | 8 | /* 9 | * ----------------------------------------------------------------------- 10 | * | PATTERN | ... | 11 | * ----------------------------------------------------------------------- 12 | * | INSTRUMENT1 | INSTRUMENT 2 | ... | ... | 13 | * ----------------------------------------------------------------------- 14 | * | ACTIVES | MUTES | SUBSTEPS | ACTIVES | MUTES | SUBSTEPS | ... | ... | 15 | * ----------------------------------------------------------------------- 16 | * 17 | */ 18 | 19 | class FlashStepMemory : public IStepMemory 20 | { 21 | public: 22 | FlashStepMemory(IHWLayer * hwLayer); 23 | virtual DrumStep getDrumStep( unsigned char instrumentID, unsigned char pattern, unsigned char step); 24 | virtual bool getNextActiveDrumStep( unsigned char instrumentID, unsigned char pattern, unsigned char & step, DrumStep & drumStep); 25 | virtual bool setDrumStep(unsigned char instrumentID, unsigned char pattern, unsigned char step, DrumStep stepData); 26 | virtual void getActivesAndMutesForNote(unsigned char instrumentID, unsigned char pattern, unsigned char windowIndex, unsigned char * data); 27 | virtual void getPatternSettings(unsigned char patternIndex, unsigned char * settings); 28 | virtual void setPatternSettings(unsigned char patternIndex, unsigned char * settings); 29 | private: 30 | IHWLayer * hwLayer_; 31 | }; 32 | 33 | #endif // FLASHSTEPMEMORY_H 34 | -------------------------------------------------------------------------------- /interpolatingBuffer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef INTERPOLATING_BUFFER_H_ 3 | #define INTERPOLATING_BUFFER_H_ 4 | 5 | #include 6 | 7 | 8 | //#include "basic.h" 9 | 10 | #include 11 | 12 | class interpolatingBuffer { 13 | 14 | public: 15 | void init(uint8_t channel); 16 | void setBastlCyclesPerPeriod(uint16_t _steps){periodInSteps=_steps;}; 17 | void loopRandom(bool _loopRandom){ loopState=_loopRandom;}; 18 | void interpolateMode(bool _interpolateMode){ interpolate=_interpolateMode;}; 19 | void setInterpolationAmount(uint8_t _interpolationAmount){ interpolateAmount=_interpolationAmount; }; 20 | void setSmootingAmount(uint16_t _smoothingAmount){ smoothingAmount=_smoothingAmount; }; 21 | 22 | void update(); 23 | void setStepValue(uint8_t _step,uint8_t _value){ buffer[_step]=_value; }; 24 | void setStep(uint8_t _step); 25 | void addRandomStep(); 26 | void addSmoothStep(uint8_t _value); 27 | void sync(); 28 | void setCurrentStep(uint8_t _step){ step=_step;}; 29 | uint8_t getCurrentValue(); 30 | 31 | 32 | private: 33 | bool loopState; 34 | uint8_t intCh; 35 | bool interpolate; 36 | uint8_t buffer[32]; 37 | uint8_t smoothBuffer[32]; 38 | uint8_t smoothingStep; 39 | uint8_t step; 40 | uint8_t interpolateAmount; 41 | uint16_t smoothingAmount; 42 | uint16_t periodInSteps; 43 | uint16_t smallSteps; 44 | uint16_t smoothSteps; 45 | uint16_t interpolatedSteps; 46 | uint16_t interpolateInSteps; 47 | uint8_t interpolateStep; 48 | void rotateBuffer(); 49 | void rotateSmoothBuffer(); 50 | void incrementPhase(); 51 | uint8_t calculateSmoothAverage(); 52 | //void calcCurrentValue(); 53 | 54 | }; 55 | 56 | 57 | 58 | 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /LFOSimple.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * LFOSimple.cpp 3 | * 4 | * Created on: 07.04.2015 5 | * Author: user 6 | */ 7 | 8 | 9 | #include "LFOSimple.h" 10 | 11 | 12 | void LFOSimple::setWaveform(Waveform val) { 13 | waveform = val; 14 | } 15 | 16 | 17 | void LFOSimple::setNumbStepsToSkip(uint8_t stepsToSkip) { 18 | 19 | uint16_t val = 257-stepsToSkip; 20 | 21 | numbPhaseStepsToSkip = uint32_t(65536)/val; 22 | } 23 | 24 | 25 | 26 | uint8_t LFOSimple::calcOutput() { 27 | 28 | // check if step will be skipped due to resolution 29 | uint16_t phaseStepsSinceLast = currentPhase-lastUnskippedPhase; 30 | 31 | 32 | // Apply Flopping 33 | if ((currentStep & flopVector) != 0) { 34 | return 0; 35 | } 36 | 37 | // check if resolution is taking affect 38 | if (phaseStepsSinceLast < numbPhaseStepsToSkip) { 39 | return currentOutput; 40 | } else { 41 | lastUnskippedPhase += numbPhaseStepsToSkip; 42 | } 43 | 44 | 45 | // Calculate Basic Waveform 46 | switch (waveform) { 47 | case SAW: 48 | currentOutput = currentStep; 49 | break; 50 | case TRIANGLE: { 51 | if (currentStep < 128) currentOutput = currentStep*2; 52 | else currentOutput = 255-((currentStep*2)-255); 53 | break; 54 | } 55 | } 56 | 57 | // Apply Overflowing 58 | if (currentOutput > thres) { 59 | if (isFolding) { 60 | uint8_t sectorNumber = currentOutput/thres; 61 | if (sectorNumber & 1) currentOutput = thres - (currentOutput % thres); 62 | else currentOutput = currentOutput % thres; 63 | } else { 64 | currentOutput = currentOutput % thres; 65 | } 66 | } 67 | 68 | // apply XOR Bits 69 | currentOutput ^= xorVector; 70 | 71 | return currentOutput; 72 | 73 | } 74 | -------------------------------------------------------------------------------- /BastlMetronome.h: -------------------------------------------------------------------------------- 1 | /* 2 | * IStepper.h 3 | * 4 | * Created on: Jul 16, 2014 5 | * Author: Martin Baar 6 | */ 7 | 8 | #ifndef METRONOME_H_ 9 | #define METRONOME_H_ 10 | 11 | #include "IHWLayer.h" 12 | 13 | class BastlMetronome { 14 | 15 | public: 16 | 17 | BastlMetronome(); 18 | void setStepCallback(void (*stepCallback)()); 19 | void setBPM(unsigned int bpm, unsigned int timeUnitsPerSecond); 20 | void update(unsigned int elapsedTimeUnits); 21 | void sync(); 22 | unsigned char getQuantizedStep(unsigned char quantization, bool & played); 23 | unsigned char getCurrentStepIndex(); 24 | protected: 25 | bool running_; 26 | bool stopAfterNextStep_; 27 | void (*stepCallback_)(); 28 | virtual unsigned char getTimeUnitsPerStep(); 29 | void start(unsigned int elapsedTimeUnits); 30 | void stop(); 31 | void stopAfterNextStep(); 32 | private: 33 | enum QuantizedShift {UP, DOWN}; 34 | 35 | unsigned int lastElapsedTimeUnits_; 36 | unsigned int timeUnitsPerStep_; 37 | unsigned char currentGlobalStep_; 38 | unsigned char quatizedStep_; 39 | QuantizedShift shift_; 40 | }; 41 | 42 | 43 | inline unsigned char BastlMetronome::getCurrentStepIndex() { 44 | return currentGlobalStep_; 45 | } 46 | 47 | inline void BastlMetronome::start(unsigned int elapsedTimeUnits) { 48 | running_ = true; 49 | lastElapsedTimeUnits_ = elapsedTimeUnits; 50 | } 51 | 52 | inline void BastlMetronome::stop() { 53 | running_ = false; 54 | } 55 | 56 | inline void BastlMetronome::stopAfterNextStep() { 57 | stopAfterNextStep_ = true; 58 | } 59 | 60 | inline void BastlMetronome::setStepCallback(void (*stepCallback)()) { 61 | stepCallback_ = stepCallback; 62 | } 63 | 64 | #endif /* METRONOME_H_ */ 65 | -------------------------------------------------------------------------------- /MIDICommand.h: -------------------------------------------------------------------------------- 1 | #ifndef MIDIMESSAGE_H 2 | #define MIDIMESSAGE_H 3 | 4 | class MIDICommand 5 | { 6 | public: 7 | enum MIDICommandType {NOTEON, NOTEOFF}; 8 | MIDICommand(); 9 | MIDICommand(MIDICommandType type, unsigned char channel, unsigned char note, unsigned char velocity); 10 | MIDICommandType getType(); 11 | void setType(const MIDICommandType & type); 12 | unsigned char getNote(); 13 | void setNote(const unsigned char & note); 14 | unsigned char getVelocity(); 15 | void setVelocity(const unsigned char & velocity); 16 | unsigned char getChannel(); 17 | void setChannel(const unsigned char & channel); 18 | 19 | private: 20 | MIDICommandType type_; 21 | unsigned char channel_; 22 | unsigned char note_; 23 | unsigned char velocity_; 24 | 25 | 26 | }; 27 | 28 | inline MIDICommand::MIDICommandType MIDICommand::getType() 29 | { 30 | return type_; 31 | } 32 | 33 | inline void MIDICommand::setType(const MIDICommand::MIDICommandType & type) 34 | { 35 | type_ = type; 36 | } 37 | 38 | inline unsigned char MIDICommand::getNote() 39 | { 40 | return note_; 41 | } 42 | inline void MIDICommand::setNote(const unsigned char & note) 43 | { 44 | note_ = note; 45 | } 46 | inline unsigned char MIDICommand::getVelocity() 47 | { 48 | return velocity_; 49 | } 50 | 51 | inline void MIDICommand::setVelocity(const unsigned char & velocity) 52 | { 53 | velocity_ = velocity; 54 | } 55 | 56 | inline unsigned char MIDICommand::getChannel() 57 | { 58 | return channel_; 59 | } 60 | 61 | inline void MIDICommand::setChannel(const unsigned char & channel) 62 | { 63 | channel_ = channel; 64 | } 65 | 66 | #endif // MIDIMESSAGE_H 67 | -------------------------------------------------------------------------------- /shiftRegisters.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * shiftRegisters.cpp 3 | * 4 | * Created on: 06.07.2014 5 | * Author: user 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | 14 | shiftRegisterBasic::shiftRegisterBasic() { 15 | //should not be called 16 | } 17 | 18 | void shiftRegisterBasic::setup( 19 | volatile uint8_t* srck_port, 20 | volatile uint8_t* srck_ddr, 21 | uint8_t srck_num, 22 | volatile uint8_t* rck_port, 23 | volatile uint8_t* rck_ddr, 24 | uint8_t rck_num, 25 | volatile uint8_t* ser_port, 26 | volatile uint8_t* ser_ddr, 27 | uint8_t ser_num) { 28 | 29 | //save pointers to ports 30 | this->srck_port = srck_port; 31 | this->srck_num = srck_num; 32 | this->rck_port = rck_port; 33 | this->rck_num = rck_num; 34 | this->ser_port = ser_port; 35 | this->ser_num = ser_num; 36 | 37 | 38 | //set pins as outputs 39 | setHigh(*srck_ddr,srck_num); 40 | setHigh(*rck_ddr,rck_num); 41 | setHigh(*ser_ddr,ser_num); 42 | 43 | //initialize clocks to low 44 | setLow(*rck_port,rck_num); 45 | setLow(*srck_port,srck_num); 46 | 47 | } 48 | 49 | void shiftRegisterBasic::write(uint8_t byte) { 50 | 51 | cli(); 52 | 53 | uint8_t dataHigh = *ser_port | (1<> index) & 1) *ser_port = dataHigh; 59 | else *ser_port = dataLow; 60 | 61 | //clock it in. only set bits to not influence SER port 62 | uint8_t clkHigh = *srck_port | (1< 9 | #include "ILEDHW.h" 10 | 11 | class IHWLayer : public ILEDHW { 12 | public: 13 | 14 | enum ButtonState{UP, DOWN}; 15 | enum EventType {EMPTY, BTN_DOWN, BTN_UP, KNOB_TWIST}; 16 | 17 | // Buttons // 18 | virtual ButtonState getButtonState(unsigned char index) = 0; 19 | 20 | // Knobs // 21 | virtual unsigned char getKnobValue(unsigned char index) = 0; 22 | virtual void freezeKnob(uint8_t number, uint8_t value) = 0; 23 | virtual void setKnobLED(uint8_t number, uint8_t value) = 0; 24 | virtual void setKnobLEDTracking(uint8_t number, bool) = 0; 25 | 26 | 27 | // RAM // 28 | virtual unsigned char readSRAM(long address) = 0; 29 | virtual void readSRAM(long address, unsigned char * data, unsigned int size) = 0; 30 | virtual void writeSRAM(long address, unsigned char data) = 0; 31 | virtual void writeSRAM(long address, unsigned char * data, unsigned int size) = 0; 32 | 33 | // Timing 34 | virtual unsigned int getElapsedBastlCycles() = 0; 35 | virtual unsigned int getBastlCyclesPerSecond() = 0; 36 | 37 | // EEPROM 38 | virtual bool writeEEPROM(uint16_t address, uint8_t* byteArray, uint16_t numbBytes); 39 | virtual void readEEPROM(uint16_t address, uint8_t* byteArray, uint16_t numbBytes); 40 | 41 | // general operation 42 | virtual void giveSomeTime(); 43 | virtual void giveAllTime(); 44 | 45 | }; 46 | 47 | struct hardwareEvent{ 48 | uint8_t number; 49 | IHWLayer::EventType type; 50 | uint16_t time; 51 | }; 52 | 53 | const hardwareEvent emptyEvent = {255,IHWLayer::EMPTY,0}; 54 | 55 | 56 | #endif // IHWLAYER_H 57 | -------------------------------------------------------------------------------- /RadioButtons.cpp: -------------------------------------------------------------------------------- 1 | #include "RadioButtons.h" 2 | 3 | //#define DEBUG 4 | 5 | #ifdef DEBUG 6 | #include 7 | #endif 8 | 9 | void RadioButtons::init(unsigned char * buttonIndexes, unsigned char count) { 10 | buttonIndexes_ = buttonIndexes; 11 | buttonCount_ = count; 12 | selectedButton_ = 0; 13 | lastDownButton_ = 255; 14 | for (unsigned char i = 0; i < buttonCount_; i++) { 15 | if (LEDsAndButtonsHWWrapper::isButtonDown(buttonIndexes_[i])) { 16 | lastDownButton_ = i; 17 | } 18 | } 19 | buttonSelected_ = false; 20 | } 21 | 22 | void RadioButtons::update() { 23 | for (unsigned char i = 0; i < buttonCount_; i++) { 24 | bool buttonDown = LEDsAndButtonsHWWrapper::isButtonDown(buttonIndexes_[i]); 25 | #ifdef DEBUG 26 | printf("Button: %i %s Last button down: %i\n", buttonIndexes_[i], buttonDown ? "DOWN" : "UP", lastDownButton_); 27 | #endif 28 | if (buttonDown) { 29 | //Button that is down is the same as previous one so just ignore everything 30 | if (lastDownButton_ == i) { 31 | return; 32 | } 33 | if (!buttonSelected_ || selectedButton_ != i) { 34 | setSelectedButton(i); 35 | } else { 36 | resetSelection(); 37 | } 38 | lastDownButton_ = i; 39 | return; 40 | } 41 | //Disable lastButtonDown by value that hopefully will never occur 42 | } 43 | lastDownButton_ = 255; 44 | } 45 | 46 | void RadioButtons::setSelectedButton(unsigned char selectedButton) { 47 | resetSelection(); 48 | selectedButton_ = selectedButton; 49 | buttonSelected_ = true; 50 | } 51 | 52 | 53 | bool RadioButtons::getSelectedButton(unsigned char &selectedButton) 54 | { 55 | if (buttonSelected_) { 56 | selectedButton = selectedButton_; 57 | return true; 58 | } 59 | return false; 60 | } 61 | -------------------------------------------------------------------------------- /data/test/DummyStepMemory.cpp: -------------------------------------------------------------------------------- 1 | #include "DummyStepMemory.h" 2 | 3 | //#define DEBUG 4 | #ifdef DEBUG 5 | 6 | #include 7 | 8 | #endif 9 | 10 | DummyStepMemory::DummyStepMemory() { 11 | DrumStep::DrumVelocityType substeps[4] = {DrumStep::OFF, DrumStep::OFF, DrumStep::OFF, DrumStep::OFF}; 12 | for (int i = 0; i < DRUM_STEPS; i ++) { 13 | drumSteps_[i] = DrumStep(true, true, substeps); 14 | } 15 | } 16 | 17 | DrumStep DummyStepMemory::getDrumStep(unsigned char instrumentID, unsigned char pattern, unsigned char step) { 18 | return drumSteps_[instrumentID * DRUM_PATTERNS * STEPS_PER_PATTERN + pattern * STEPS_PER_PATTERN + step] ; 19 | } 20 | 21 | bool DummyStepMemory::setDrumStep(unsigned char instrumentID, unsigned char pattern, unsigned char step, DrumStep stepData) { 22 | drumSteps_[instrumentID * DRUM_PATTERNS * STEPS_PER_PATTERN + pattern * STEPS_PER_PATTERN + step] = stepData; 23 | return true; 24 | 25 | } 26 | 27 | bool DummyStepMemory::getNextActiveDrumStep(unsigned char instrumentID, unsigned char pattern, unsigned char & step, DrumStep & drumStep) 28 | { 29 | unsigned char currentStepIndex = step; 30 | #ifdef DEBUG 31 | unsigned char index = (instrumentID * DRUM_PATTERNS * STEPS_PER_PATTERN) + (pattern * STEPS_PER_PATTERN) + step; 32 | printf("DummyStepMemory::getNextActiveDrumStep index in array : %i , length of array %i\ns", index, DRUM_STEPS); 33 | #endif 34 | drumStep = drumSteps_[instrumentID * DRUM_PATTERNS * STEPS_PER_PATTERN + pattern * STEPS_PER_PATTERN + step]; 35 | while (!drumStep.isActive()) { 36 | step = (step + 1) % STEPS_PER_PATTERN; 37 | if (step == currentStepIndex) { 38 | return false; 39 | } 40 | drumStep = drumSteps_[instrumentID * DRUM_PATTERNS * STEPS_PER_PATTERN + pattern * STEPS_PER_PATTERN + step]; 41 | } 42 | return true; 43 | } 44 | -------------------------------------------------------------------------------- /Tapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tapper.h 3 | * 4 | * Created on: Sep 5, 2014 5 | * Author: bastl 6 | */ 7 | 8 | #ifndef TAPPER_H_ 9 | #define TAPPER_H_ 10 | 11 | #include "basic.h" 12 | #include "ITapper.h" 13 | 14 | 15 | 16 | 17 | class Tapper { 18 | public: 19 | Tapper(); 20 | ~Tapper(); 21 | 22 | // Initialize class. 23 | // maxStepLengthInTimeUnits defines the the slowest tap tempo that is tracked 24 | // maxRelativeDeviation define how easily a tap cycle is restarted 25 | void init(uint16_t maxStepLengthInTimeUnits, uint8_t maxRelativeDeviation=20); 26 | 27 | // tap it! 28 | void tap(uint16_t tapTime); 29 | 30 | // When the tap cycle gets reset, this callback is called 31 | void setResetCallback(void (*resetCallback)(uint16_t)); 32 | 33 | 34 | void setStepsPerTap(uint8_t stepsPerTap); 35 | uint16_t getTimeUnitsPerStep(); 36 | void setStepCallBack(void (*makeStep)()); 37 | bool anyStepDetected(); 38 | 39 | private: 40 | 41 | static const uint8_t historyLen = 4; 42 | uint16_t history[4]; 43 | uint8_t historyHead; 44 | uint8_t historyFillCount; 45 | void addToHistory(uint16_t val); 46 | uint16_t getAverage(); 47 | uint16_t getLast(); 48 | 49 | uint16_t lastTapTime; 50 | uint8_t stepsPerTap_; 51 | uint16_t maxStepLengthInTimeUnits; 52 | uint8_t maxRelativeDeviation; 53 | uint8_t firstOfCycle; 54 | void (*resetCallback)(uint16_t); 55 | void (*makeStep_)(); 56 | }; 57 | 58 | inline void Tapper::setStepsPerTap(uint8_t stepsPerTap) { 59 | stepsPerTap_ = stepsPerTap; 60 | } 61 | 62 | inline uint16_t Tapper::getTimeUnitsPerStep() { 63 | return (getAverage() + stepsPerTap_/2) / stepsPerTap_; 64 | } 65 | 66 | inline void Tapper::setResetCallback(void (*ptr)(uint16_t)) { 67 | resetCallback = ptr; 68 | } 69 | 70 | inline void Tapper::setStepCallBack(void (*makeStep)()) { 71 | makeStep_ = makeStep; 72 | } 73 | 74 | inline bool Tapper::anyStepDetected() { 75 | return historyFillCount > 0; 76 | } 77 | 78 | #endif /* TAPPER_H_ */ 79 | -------------------------------------------------------------------------------- /portManipulations.h: -------------------------------------------------------------------------------- 1 | /* 2 | * portManipulations.h 3 | * 4 | * Created on: 06.07.2014 5 | * Author: user 6 | * thanks to: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=91304 7 | */ 8 | 9 | #ifndef PORTMANIPULATIONS_H_ 10 | #define PORTMANIPULATIONS_H_ 11 | 12 | // convenient macros for port manipulation 13 | // usage: 14 | // - define pins like this (example: PB0) 15 | // #define NAME B,0 16 | // and us those defines as arguments for the following macros 17 | // 18 | // - bit_set() sets bit to HIGH 19 | // bit_clear() sets bit to LOW 20 | // bit_toggle() flip bit 21 | // bit_read() returns the current value of the bit 22 | // bit_dir_outp() sets data direction to output 23 | // bit_dir_inp() sets data direction to input 24 | // bit_read_in() performs quick digitalRead 25 | 26 | 27 | #define bit_set(...) bit_set_(__VA_ARGS__) 28 | #define bit_set_(x,y) PORT ## x |= 1< 8 | #endif 9 | 10 | Switches::Switches() : 11 | buttonIndexes_(0), 12 | buttonCount_(0), 13 | lastStates_(0), 14 | statuses_(0), 15 | changeOnEvent_(IButtonHW::DOWN), 16 | useLEDs_(false) 17 | { 18 | } 19 | 20 | void Switches::init(unsigned char * buttonIndexes, 21 | unsigned char count, 22 | bool useLEDs, 23 | IButtonHW::ButtonState changeOnEvent) { 24 | buttonIndexes_ = buttonIndexes; 25 | buttonCount_ = count; 26 | changeOnEvent_ = changeOnEvent; 27 | useLEDs_ = useLEDs; 28 | ignoreButton_ = count; 29 | } 30 | 31 | void Switches::computeIgnoreButton() { 32 | for (unsigned char i = 0; i < buttonCount_; i++) { 33 | if (LEDsAndButtonsHWWrapper::isButtonDown(buttonIndexes_[i])) { 34 | ignoreButton_ = i; 35 | } 36 | } 37 | } 38 | 39 | void Switches::update() { 40 | for (unsigned char i = 0; i < buttonCount_; i++) { 41 | bool buttonDown = LEDsAndButtonsHWWrapper::isButtonDown(buttonIndexes_[i]); 42 | #ifdef DEBUG 43 | printf("Button %d(%d) %s\n", i, buttonIndexes_[i], buttonDown ? "down" : "up"); 44 | #endif 45 | if (((changeOnEvent_ == IButtonHW::DOWN) && !GETBIT(lastStates_, i) && buttonDown) || 46 | ((changeOnEvent_ == IButtonHW::UP) && GETBIT(lastStates_, i) && !buttonDown) ) { 47 | if (ignoreButton_ == i) { 48 | ignoreButton_ = buttonCount_ + 1; 49 | } else { 50 | setStatus(i, !GETBIT(statuses_, i)); 51 | } 52 | } 53 | setBit(lastStates_, i, buttonDown); 54 | } 55 | } 56 | 57 | bool Switches::getStatus(unsigned char buttonIndex) 58 | { 59 | return GETBIT(statuses_, buttonIndex) == 1; 60 | } 61 | 62 | void Switches::setStatus(unsigned char buttonIndex, bool value) 63 | { 64 | if (value) { 65 | SETBITTRUE(statuses_, buttonIndex); 66 | } else { 67 | SETBITFALSE(statuses_, buttonIndex); 68 | } 69 | if (useLEDs_) { 70 | LEDsAndButtonsHWWrapper::setLED(buttonIndexes_[buttonIndex], value ? ILEDHW::ON : ILEDHW::OFF); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /SimplifiedTapper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SimplifiedTapper.cpp 3 | * 4 | * Created on: Sep 5, 2014 5 | * Author: bastl 6 | */ 7 | 8 | #include "SimplifiedTapper.h" 9 | //#include 10 | 11 | //#define DEBUG 12 | #ifdef DEBUG 13 | #include 14 | #endif 15 | 16 | SimplifiedTapper::SimplifiedTapper() : stepsInRow_(-1), 17 | lastTapTime_(0), 18 | currentTapTime_(0), 19 | stepsPerTap_(16), 20 | maxStepLengthInTimeUnits_(2500), 21 | maxStepDeviationInTImeUnits_(700), 22 | makeStep_(0) { 23 | 24 | } 25 | 26 | SimplifiedTapper::~SimplifiedTapper() { 27 | 28 | } 29 | void SimplifiedTapper::init(unsigned int maxStepLengthInTimeUnits, unsigned int maxStepDeviationInTImeUnits) 30 | { 31 | maxStepLengthInTimeUnits_ = maxStepLengthInTimeUnits; 32 | maxStepDeviationInTImeUnits_ = maxStepDeviationInTImeUnits; 33 | } 34 | 35 | void SimplifiedTapper::tap(unsigned int tapTime) 36 | { 37 | #ifdef DEBUG 38 | printf("Tapper::tap received tap with tap time %d.\n",tapTime); 39 | #endif 40 | // Reset values when first tap or tap over defined max tap deviation 41 | if ((stepsInRow_ == -1) || 42 | (lastTapTime_ + maxStepLengthInTimeUnits_ < tapTime) || 43 | ((stepsInRow_ > 0) && ((lastTapTime_ + currentTapTime_ - tapTime) > (0.5 * currentTapTime_)))) 44 | { 45 | lastTapTime_ = tapTime; 46 | currentTapTime_ = 0; 47 | stepsInRow_ = 0; 48 | if (makeStep_ != 0) { 49 | #ifdef DEBUG 50 | printf("Tapper::tap Sending step command (First Step).\n"); 51 | #endif 52 | makeStep_(); 53 | } 54 | } 55 | else 56 | { 57 | unsigned int lastTapLength = tapTime - lastTapTime_; 58 | lastTapTime = lastTapLength; 59 | currentTapTime_ = (unsigned int)((((unsigned long)currentTapTime_ * (unsigned long)stepsInRow_) + (unsigned long)lastTapLength) / (unsigned long)(stepsInRow_ + 1)); 60 | if (stepsInRow_ < 4) { //novinka 61 | stepsInRow_++; 62 | } 63 | lastTapTime_ = tapTime; 64 | if (makeStep_ != 0) { 65 | #ifdef DEBUG 66 | printf("Tapper::tap Sending step command (Continous Step).\n"); 67 | #endif 68 | makeStep_(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /shiftRegisters.h: -------------------------------------------------------------------------------- 1 | /* 2 | * shiftRegisters.h 3 | * 4 | * Created on: 06.07.2014 5 | * Author: user 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #ifndef SHIFTREGISTERS_H_ 12 | #define SHIFTREGISTERS_H_ 13 | 14 | 15 | 16 | // Class to write data to 595 type shift registers 17 | // 18 | // after creating an instance, use setup() to set the pins you are using. three pins are need for operation: 19 | // - SER: data input to the shift register 20 | // - SRCK: clock for taking the value from SER to the first storage register and shifting the other one step ahead 21 | // - RCK: enable the output of the shift register 22 | // 23 | // - if you have several shift registers daisy chained, you can use write() multiple times 24 | // - shifting out a byte takes ~70us due to continuous pointer dereferencing but you can access multiple shift registers with multiple instances 25 | 26 | class shiftRegisterBasic { 27 | public: 28 | 29 | // empty. do not use! 30 | shiftRegisterBasic(); 31 | 32 | // set up the pins you want to use 33 | void setup( 34 | volatile uint8_t* srck_port, 35 | volatile uint8_t* srck_ddr, 36 | uint8_t srck_num, 37 | volatile uint8_t* rck_port, 38 | volatile uint8_t* rck_ddr, 39 | uint8_t rck_num, 40 | volatile uint8_t* ser_port, 41 | volatile uint8_t* ser_ddr, 42 | uint8_t ser_num); 43 | 44 | // write a byte to the shift register 45 | // you have to enable the output manually 46 | void write(uint8_t byte); 47 | 48 | // enable output 49 | inline void enableOutput() { 50 | setHigh(*rck_port,rck_num); 51 | setLow(*rck_port,rck_num); 52 | } 53 | 54 | // clock in a single bit 55 | inline void serClkIn() { 56 | setHigh(*srck_port,srck_num); 57 | setLow(*srck_port,srck_num); 58 | } 59 | 60 | // convenient method for setting the value of SER pin 61 | inline void setDataBit(bool value) { 62 | if (value) setHigh(*ser_port,ser_num); 63 | else setLow(*ser_port,ser_num); 64 | } 65 | 66 | 67 | private: 68 | volatile uint8_t* srck_port; // the port SRCK pin is on 69 | uint8_t srck_num; // the number of the SRCK pin inside the SRCK port 70 | volatile uint8_t* rck_port; // ..same here 71 | uint8_t rck_num; // ... 72 | volatile uint8_t* ser_port; 73 | uint8_t ser_num; 74 | }; 75 | 76 | 77 | #endif /* SHIFTREGISTERS_H_ */ 78 | 79 | -------------------------------------------------------------------------------- /LFORandom.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * LFORandom.cpp 3 | * 4 | * Created on: 07.04.2015 5 | * Author: user 6 | */ 7 | 8 | 9 | #include "LFORandom.h" 10 | #include "random.h" 11 | 12 | void LFORandom::step() { 13 | LFO::step(); 14 | 15 | // pick a new value whenever phase wraps, which indicates the start of a period 16 | if (currentPhase < phaseIncrement) thisStepDetailed = ((bastlRandom::byte()<<8) | bastlRandom::byte()); 17 | 18 | addToBuffer(((uint32_t)getBufferAverage()*(smoothness)+(uint32_t)thisStepDetailed*(255-smoothness))/255); 19 | } 20 | 21 | 22 | 23 | 24 | 25 | void LFORandom::setSmoothness(uint8_t val) { 26 | smoothness = val; 27 | } 28 | 29 | 30 | 31 | 32 | // mapping from smoothness to reduction of buffer length 33 | uint8_t mappedBufferLen(uint8_t val) { 34 | if (val < 5) return 31; 35 | else if (val < 7) return 25; 36 | else if (val < 10) return 15; 37 | else if (val < 20) return 10; 38 | else if (val < 30) return 5; 39 | else return 0; 40 | } 41 | 42 | 43 | void LFORandom::addToBuffer(uint16_t val) { 44 | buffer[bufferPos] = val; 45 | bufferPos++; 46 | if (bufferPos == bufferSize) bufferPos = 0; 47 | } 48 | 49 | 50 | uint16_t LFORandom::getBufferAverage() { 51 | 52 | // get average of a certain number of previous elements depending on smoothness 53 | uint8_t numbElements = bufferSize-mappedBufferLen(smoothness); 54 | 55 | // start from last stored value 56 | uint8_t index = bufferPos-1; 57 | if (index == 255) index = bufferSize-1; 58 | 59 | // sum all those elements... 60 | uint32_t sum = 0; 61 | for (uint8_t count = 0; count> 8; 81 | 82 | // Apply Overflowing 83 | if (currentOutput > thres) { 84 | if (isFolding) { 85 | uint8_t sectorNumber = currentOutput/thres; 86 | if (sectorNumber & 1) currentOutput = thres - (currentOutput % thres); 87 | else currentOutput = currentOutput % thres; 88 | } else { 89 | currentOutput = currentOutput % thres; 90 | } 91 | } 92 | 93 | // apply xor 94 | currentOutput ^= xorVector; 95 | 96 | return currentOutput; 97 | 98 | } 99 | -------------------------------------------------------------------------------- /NoVelocityStepMemory.h: -------------------------------------------------------------------------------- 1 | #ifndef FLASHSTEPMEMORY_H 2 | #define FLASHSTEPMEMORY_H 3 | 4 | #include "IHWLayer.h" 5 | #include "IStepMemory.h" 6 | #include "DrumStep.h" 7 | #include "RackInstrumentDefinitions.h" 8 | 9 | /* 10 | * ----------------------------------------------------------------------- 11 | * | PATTERN | ... | 12 | * ----------------------------------------------------------------------- 13 | * | INSTRUMENT1 | INSTRUMENT 2 | ... | ... | 14 | * ----------------------------------------------------------------------- 15 | * | ACTIVES | MUTES | SUBSTEPS | ACTIVES | MUTES | SUBSTEPS | ... | ... | 16 | * ----------------------------------------------------------------------- 17 | * 18 | */ 19 | 20 | class NoVelocityStepMemory : public IStepMemory 21 | { 22 | public: 23 | NoVelocityStepMemory(); 24 | virtual ~NoVelocityStepMemory(); 25 | virtual DrumStep getDrumStep( unsigned char instrumentID, unsigned char step); 26 | virtual bool getNextActiveDrumStep( unsigned char instrumentID, unsigned char & step, DrumStep & drumStep); 27 | virtual bool setDrumStep(unsigned char instrumentID, unsigned char step, DrumStep stepData); 28 | virtual void getMutesForNote(unsigned char instrumentID, unsigned char windowIndex, unsigned char *& data); 29 | virtual void setDataReference(unsigned char * dataReference); 30 | virtual unsigned char * getDataReference(); 31 | virtual void getAllInstrumentActivesFor16Steps(unsigned char fromIndex, ActiveMultiStatus * result); 32 | virtual void makeActiveUpTo(unsigned char instrument, unsigned char indexUpTo); 33 | virtual void makeAllInstrumentsActiveUpTo(unsigned char indexUpTo); 34 | virtual void clearStepsForInstrument(unsigned char instrument); 35 | virtual void clearStepsForAllInstruments(); 36 | virtual unsigned char getNumberOfActives(unsigned char instrument); 37 | private: 38 | unsigned char * data_; 39 | void getDrumStepDataPointers(unsigned char instrumentID, unsigned char step, 40 | unsigned char *& mutes, unsigned char *& data); 41 | unsigned int getDataOffset(unsigned char instrumentID, unsigned char pan); 42 | }; 43 | 44 | inline void NoVelocityStepMemory::setDataReference(unsigned char * dataReference) { 45 | data_ = dataReference; 46 | } 47 | 48 | inline unsigned char * NoVelocityStepMemory::getDataReference() { 49 | return data_; 50 | } 51 | 52 | #endif // FLASHSTEPMEMORY_H 53 | -------------------------------------------------------------------------------- /expADSR.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // ADSR.cpp 3 | // 4 | // Created by Nigel Redmon on 12/18/12. 5 | // EarLevel Engineering: earlevel.com 6 | // Copyright 2012 Nigel Redmon 7 | // 8 | // For a complete explanation of the ADSR envelope generator and code, 9 | // read the series of articles by the author, starting here: 10 | // http://www.earlevel.com/main/2013/06/01/envelope-generators/ 11 | // 12 | // License: 13 | // 14 | // This source code is provided as is, without warranty. 15 | // You may copy and distribute verbatim copies of this document. 16 | // You may modify and use this source code to create binary code for your own purposes, free or commercial. 17 | // 18 | 19 | #include "expADSR.h" 20 | #include 21 | 22 | 23 | ADSR::ADSR(void) { 24 | reset(); 25 | setAttackRate(0); 26 | setDecayRate(0); 27 | setReleaseRate(0); 28 | setSustainLevel(1.0); 29 | setTargetRatioA(0.3); 30 | setTargetRatioDR(0.0001); 31 | setLoop(false); 32 | } 33 | 34 | ADSR::~ADSR(void) { 35 | } 36 | void ADSR::sync(){ 37 | 38 | } 39 | void ADSR::setAttackRate(float rate) { 40 | attackRate = rate; 41 | attackCoef = calcCoef(rate, targetRatioA); 42 | attackBase = (1.0 + targetRatioA) * (1.0 - attackCoef); 43 | } 44 | 45 | void ADSR::setDecayRate(float rate) { 46 | decayRate = rate; 47 | decayCoef = calcCoef(rate, targetRatioDR); 48 | decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef); 49 | } 50 | 51 | void ADSR::setReleaseRate(float rate) { 52 | releaseRate = rate; 53 | releaseCoef = calcCoef(rate, targetRatioDR); 54 | releaseBase = -targetRatioDR * (1.0 - releaseCoef); 55 | } 56 | 57 | float ADSR::calcCoef(float rate, float targetRatio) { 58 | return exp(-log((1.0 + targetRatio) / targetRatio) / rate); 59 | } 60 | 61 | void ADSR::setSustainLevel(float level) { 62 | sustainLevel = level; 63 | decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef); 64 | } 65 | 66 | void ADSR::setTargetRatioA(float targetRatio) { 67 | if (targetRatio < 0.000000001) 68 | targetRatio = 0.000000001; // -180 dB 69 | targetRatioA = targetRatio; 70 | attackBase = (1.0 + targetRatioA) * (1.0 - attackCoef); 71 | } 72 | 73 | void ADSR::setTargetRatioDR(float targetRatio) { 74 | if (targetRatio < 0.000000001) 75 | targetRatio = 0.000000001; // -180 dB 76 | targetRatioDR = targetRatio; 77 | decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef); 78 | releaseBase = -targetRatioDR * (1.0 - releaseCoef); 79 | } 80 | -------------------------------------------------------------------------------- /fastArithmetic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * fastArithmetic.h 3 | * 4 | * Created on: 05.08.2014 5 | * Author: user 6 | */ 7 | 8 | #ifndef FASTARITHMETIC_H_ 9 | #define FASTARITHMETIC_H_ 10 | 11 | static inline int16_t S16U8MulShift8(int16_t a, uint8_t b) { 12 | int16_t result; 13 | asm( 14 | "eor %B0, %B0" "\n\t" 15 | "mul %A1, %A2" "\n\t" 16 | "mov %A0, r1" "\n\t" 17 | "mulsu %B1, %A2" "\n\t" 18 | "add %A0, r0" "\n\t" 19 | "adc %B0, r1" "\n\t" 20 | "eor r1, r1" "\n\t" 21 | : "=&r" (result) 22 | : "a" (a), "a" (b) 23 | ); 24 | return result; 25 | } 26 | 27 | static inline uint8_t U8U8MulShift8(uint8_t a, uint8_t b) { 28 | uint8_t result; 29 | asm( 30 | "mul %1, %2" "\n\t" 31 | "mov %0, r1" "\n\t" 32 | "eor r1, r1" "\n\t" 33 | : "=r" (result) 34 | : "a" (a), "a" (b) 35 | ); 36 | return result; 37 | } 38 | static inline uint16_t U16U8MulShift8(uint16_t a, uint8_t b) { 39 | uint16_t result; 40 | asm( 41 | "eor %B0, %B0" "\n\t" 42 | "mul %A1, %A2" "\n\t" 43 | "mov %A0, r1" "\n\t" 44 | "mul %B1, %A2" "\n\t" 45 | "add %A0, r0" "\n\t" 46 | "adc %B0, r1" "\n\t" 47 | "eor r1, r1" "\n\t" 48 | : "=&r" (result) 49 | : "a" (a), "a" (b) 50 | ); 51 | return result; 52 | } 53 | 54 | static inline int16_t S16S8MulShift8(int16_t a, int8_t b) { 55 | int16_t result; 56 | asm( 57 | "eor %B0, %B0" "\n\t" 58 | "muls %A2, %B1" "\n\t" 59 | "movw %A0, r0" "\n\t" 60 | "mulsu %A2, %A1" "\n\t" 61 | "eor r0, r0" "\n\t" 62 | "sbc %B0, r0" "\n\t" 63 | "add %A0, r1" "\n\t" 64 | "adc %B0, r0" "\n\t" 65 | "eor r1, r1" "\n\t" 66 | : "=&r" (result) 67 | : "a" (a), "a" (b) 68 | ); 69 | return result; 70 | } 71 | 72 | static inline uint8_t S16ClipU8(int16_t value) { 73 | uint8_t result; 74 | asm( 75 | "mov %0, %A1" "\n\t" // by default, copy the value. 76 | "or %B1, %B1" "\n\t" // load H to set flags. 77 | "brpl .+4" "\n\t" // if positive, skip 78 | "ldi %0, 0" "\n\t" // set to 0. 79 | "rjmp .+4" "\n\t" // and jump. 80 | "breq .+2" "\n\t" // if null, skip 81 | "ldi %0, 255" "\n\t" // set to 255 82 | : "=r" (result) 83 | : "a" (value) 84 | ); 85 | return result; 86 | } 87 | 88 | static inline int16_t Clip(int16_t value, int16_t min, int16_t max) { 89 | return value < min ? min : (value > max ? max : value); 90 | } 91 | 92 | 93 | 94 | #endif /* FASTARITHMETIC_H_ */ 95 | -------------------------------------------------------------------------------- /test/testTapper.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | #include "../Tapper.h" 6 | 7 | 8 | Tapper tapper; 9 | 10 | 11 | void cb(uint16_t time) { 12 | printf("RESETting at %u\n",time); 13 | } 14 | 15 | int main( int argc, const char* argv[] ) { 16 | 17 | tapper.init(200,10); 18 | tapper.setResetCallback(cb); 19 | 20 | // Normal tapping with ~100 21 | printf("### Normal Tapping ~100\n"); 22 | tapper.tap(0); 23 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 24 | tapper.tap(100); 25 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 26 | tapper.tap(220); 27 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 28 | tapper.tap(310); 29 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 30 | 31 | // longer tap time difference to exit cycle and tapping at ~50 32 | printf("\n###Tapping at ~50, the single resets\n"); 33 | tapper.tap(500); 34 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 35 | tapper.tap(550); 36 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 37 | tapper.tap(610); 38 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 39 | tapper.tap(655); 40 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 41 | // some single taps that indicate only hitting the first beat of bar with 42 | tapper.tap(800); 43 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 44 | tapper.tap(1100); 45 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 46 | tapper.tap(1500); 47 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 48 | 49 | printf("\n###Testdata\n"); 50 | tapper.init(2000*60.0/30); 51 | tapper.tap(49982); 52 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 53 | tapper.tap(50395); 54 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 55 | tapper.tap(50767); 56 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 57 | tapper.tap(51181); 58 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 59 | tapper.tap(21912); 60 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 61 | tapper.tap(24713); 62 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 63 | tapper.tap(27311); 64 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 65 | tapper.tap(30396); 66 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 67 | tapper.tap(33319); 68 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 69 | tapper.tap(36161); 70 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 71 | tapper.tap(38922); 72 | printf("--> speed: %u\n",tapper.getTimeUnitsPerStep()); 73 | 74 | 75 | 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | #CPP_FILES_CLASS = $(wildcard` ../*.cpp) 2 | #OBJ_FILES_CLASS = $(addprefix ../obj/,$(notdir $(CPP_FILES:.cpp=.o))) 3 | CPP_FILES = tst.cpp 4 | #OBJ_FILES = tst_step.o 5 | #LD_FLAGS= 6 | CC_FLAGS=-c -Wall -g -O0 7 | 8 | #test: $(OBJ_FILES) $(OBJ_FILES_CLASS) 9 | # g++ $(LD_FLAGS) -o $@ $^ 10 | 11 | .PHONY : check test 12 | 13 | check : test radioButtonTest switchesTest 14 | ./test 15 | ./radioButtonTest 16 | ./switchesTest 17 | 18 | test : obj/tst.o obj/Tapper.o obj/StepDivider.o obj/StepMultiplier.o obj/StepGenerator.o obj/BastlStepper.o obj/DrumStep.o obj/NoVelocityStepMemory.o obj/Step.o 19 | g++ -o $@ $^ 20 | ./test 21 | 22 | switchesTest : obj/switchesTest.o obj/Switches.o obj/HWLayerMock.o 23 | g++ -o $@ $^ 24 | ./switchesTest 25 | 26 | obj/Arpeggiator_Test.o : Arpeggiator_test.cpp 27 | g++ $(CC_FLAGS) -o $@ $< 28 | 29 | obj/Arpeggiator.o : ../Arpeggiator.cpp 30 | g++ $(CC_FLAGS) -o $@ $< 31 | 32 | obj/random.o : ../random.cpp 33 | g++ $(CC_FLAGS) -o $@ $< 34 | 35 | arpeggiatorTest : obj/Arpeggiator_Test.o obj/Arpeggiator.o obj/random.o 36 | g++ -O0 -o $@ $^ 37 | ./arpeggiatorTest 38 | 39 | obj/switchesTest.o : tstSwitches.cpp 40 | g++ $(CC_FLAGS) -o $@ $< 41 | 42 | obj/Switches.o : ../Switches.cpp 43 | g++ $(CC_FLAGS) -o $@ $< 44 | 45 | radioButtonTest : obj/radioButtonTest.o obj/RadioButtons.o obj/HWLayerMock.o 46 | g++ -o $@ $^ 47 | ./radioButtonTest 48 | 49 | obj/radioButtonTest.o : tstRadioButton.cpp 50 | g++ $(CC_FLAGS) -o $@ $< 51 | 52 | obj/RadioButtons.o : ../RadioButtons.cpp 53 | g++ $(CC_FLAGS) -o $@ $< 54 | 55 | obj/HWLayerMock.o : HWLayerMock.cpp 56 | g++ $(CC_FLAGS) -o $@ $< 57 | 58 | obj/tst.o : tst.cpp 59 | g++ $(CC_FLAGS) -o $@ $< 60 | 61 | obj/Tapper.o : ../Tapper.cpp 62 | g++ $(CC_FLAGS) -o $@ $< 63 | 64 | obj/StepDivider.o : ../../bastl-sequencing/StepDivider.cpp 65 | g++ $(CC_FLAGS) -o $@ $< 66 | 67 | obj/StepMultiplier.o : ../../bastl-sequencing/StepMultiplier.cpp 68 | g++ $(CC_FLAGS) -o $@ $< 69 | 70 | obj/StepGenerator.o : ../../bastl-sequencing/StepGenerator.cpp 71 | g++ $(CC_FLAGS) -o $@ $< 72 | 73 | obj/BastlStepper.o : ../../bastl-sequencing/BastlStepper.cpp 74 | g++ $(CC_FLAGS) -o $@ $< 75 | 76 | obj/DrumStep.o : ../DrumStep.cpp 77 | g++ $(CC_FLAGS) -o $@ $< 78 | 79 | obj/Step.o : ../Step.cpp 80 | g++ $(CC_FLAGS) -o $@ $< 81 | 82 | obj/NoVelocityStepMemory.o : ../NoVelocityStepMemory.cpp 83 | g++ $(CC_FLAGS) -o $@ $< 84 | 85 | 86 | #../obj/%.o: ../%.cpp 87 | # g++ -I../ -c -o $@ $< 88 | # 89 | #%.o : %.cpp 90 | # g++ -I../ -c -o $@ $< -I../ISequenceMemory.h 91 | 92 | clean: 93 | -rm -f obj/*.o 94 | -rm -f test 95 | 96 | -------------------------------------------------------------------------------- /test/tstSwitches.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "HWLayerMock.h" 3 | #include "../RadioButtons.h" 4 | #include "../Switches.h" 5 | #include 6 | 7 | int main( int argc, const char* argv[] ) { 8 | HWLayerMock hw; 9 | printf("Test Switches (down activated)\n"); 10 | 11 | unsigned char switchesButtons[16] = {0, 2, 4/*first used button*/, 6, 8, 10, 12, 14, 16}; 12 | Switches switches; 13 | switches.init(&hw, &switchesButtons[2], 6); 14 | 15 | hw.setButtonState(8, true); 16 | switches.update(); 17 | printf("\tTest 7 - Button pressed \t\t%s\n", switches.getStatus(2) ? "OK" : "Error"); 18 | switches.update(); 19 | printf("\tTest 8 - Button keep pressed \t\t%s\n", switches.getStatus(2) ? "OK" : "Error"); 20 | hw.setButtonState(8, false); 21 | switches.update(); 22 | printf("\tTest 9 - Button released \t\t%s\n", switches.getStatus(2) ? "OK" : "Error"); 23 | hw.setButtonState(8, true); 24 | switches.update(); 25 | printf("\tTest 10 - Button pressed again \t\t%s\n", !switches.getStatus(2) ? "OK" : "Error"); 26 | 27 | switches.setStatus(3, true); 28 | printf("\tTest 11 - Button set externally to pressed \t\t%s\n", switches.getStatus(3) ? "OK" : "Error"); 29 | switches.setStatus(3, false); 30 | printf("\tTest 12 - Button set externally to released \t\t%s\n", !switches.getStatus(3) ? "OK" : "Error"); 31 | 32 | printf("Test Switches (up activated)\n"); 33 | 34 | Switches switches2; 35 | switches2.init(&hw, &switchesButtons[2], 6, IButtonHW::UP); 36 | 37 | hw.setButtonState(12, true); 38 | switches2.update(); 39 | printf("\tTest 7 - Button pressed \t\t%s\n", !switches2.getStatus(4) ? "OK" : "Error"); 40 | switches2.update(); 41 | printf("\tTest 8 - Button keep pressed \t\t%s\n", !switches2.getStatus(4) ? "OK" : "Error"); 42 | hw.setButtonState(12, false); 43 | switches2.update(); 44 | printf("\tTest 9 - Button released \t\t%s\n", switches2.getStatus(4) ? "OK" : "Error"); 45 | hw.setButtonState(12, true); 46 | switches2.update(); 47 | printf("\tTest 10 - Button pressed again \t\t%s\n", switches2.getStatus(4) ? "OK" : "Error"); 48 | hw.setButtonState(12, false); 49 | switches2.update(); 50 | printf("\tTest 10 - Button pressed again \t\t%s\n", !switches2.getStatus(4) ? "OK" : "Error"); 51 | 52 | switches2.setStatus(3, true); 53 | printf("\tTest 11 - Button set externally to pressed \t\t%s\n", switches2.getStatus(3) ? "OK" : "Error"); 54 | switches2.setStatus(3, false); 55 | printf("\tTest 12 - Button set externally to released \t\t%s\n", !switches2.getStatus(3) ? "OK" : "Error"); 56 | } 57 | -------------------------------------------------------------------------------- /BastlMetronome.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Stepper.cpp 3 | * 4 | * Created on: Jul 16, 2014 5 | * Author: Martin Baar 6 | */ 7 | 8 | 9 | //#define DEBUG 10 | #ifdef DEBUG 11 | 12 | #include 13 | 14 | #endif 15 | 16 | #include "BastlMetronome.h" 17 | 18 | BastlMetronome::BastlMetronome(): 19 | running_(true), stopAfterNextStep_(false), stepCallback_(0), currentGlobalStep_(0), quatizedStep_(0), shift_(DOWN) { 20 | } 21 | 22 | unsigned char BastlMetronome::getQuantizedStep(unsigned char quantization, bool & played) { 23 | unsigned char result = quatizedStep_ / quantization; 24 | result = result + (quatizedStep_ % quantization > quatizedStep_ / 2) ? 1 : 0; 25 | if (quatizedStep_ % quantization == quantization / 2) { 26 | if (shift_ == DOWN) { 27 | result --; 28 | } 29 | } 30 | result *= quantization; 31 | played = result < currentGlobalStep_; 32 | return result; 33 | } 34 | 35 | void BastlMetronome::update(unsigned int elapsedTimeUnits) { 36 | 37 | quatizedStep_ = currentGlobalStep_; 38 | shift_ = DOWN; 39 | if ((elapsedTimeUnits - lastElapsedTimeUnits_) > (getTimeUnitsPerStep() / 2)) { 40 | quatizedStep_ = (quatizedStep_ + 1) % 256; 41 | shift_ = UP; 42 | } 43 | if (running_) { 44 | 45 | //Even if the value overflow which happens every ~6 minutes we should get correct value 46 | //This works in case steps are shorted than 6 minutes which is the rule we suppose we never break 47 | 48 | if ((getTimeUnitsPerStep() != 0) && ((elapsedTimeUnits - lastElapsedTimeUnits_) > getTimeUnitsPerStep())) { 49 | if (stepCallback_ != 0) { 50 | #ifdef DEBUG 51 | printf("\tSending step elapsed cycles: %d\n", elapsedCycles); 52 | #endif 53 | stepCallback_(); 54 | currentGlobalStep_ = (currentGlobalStep_ + 1) % 256; 55 | } 56 | if (stopAfterNextStep_) { 57 | #ifdef DEBUG 58 | printf("\tStopping\n", elapsedCycles); 59 | #endif 60 | stop(); 61 | } 62 | 63 | // catch the next step 64 | lastElapsedTimeUnits_ = elapsedTimeUnits; // getBastlCyclesPerStep() * ((elapsedCycles - lastElapsedCycles_) % getBastlCyclesPerStep()); 65 | } 66 | } 67 | } 68 | 69 | void BastlMetronome::sync() { 70 | if (stepCallback_ != 0) { 71 | stepCallback_(); 72 | currentGlobalStep_ = (currentGlobalStep_ + 1) % 256; 73 | } 74 | //lastElapsedTimeUnits_ = elapsedTimeUnits; 75 | } 76 | 77 | void BastlMetronome::setBPM(unsigned int bpm, unsigned int timeUnitsPerSecod) { 78 | if (bpm < 5) {bpm = 5;}; 79 | // Rounding instead of casting could be nice here but lets make it little out of sync 80 | // One beat is actually 16 bastl steps 81 | 82 | timeUnitsPerStep_ = ((timeUnitsPerSecod * 60) / bpm) / 16; 83 | } 84 | 85 | unsigned char BastlMetronome::getTimeUnitsPerStep() { 86 | return timeUnitsPerStep_; 87 | } 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | 2 | ###############***************############### 3 | Licence: 4 | Bastl Library by Vaclav Pelousek http://pelousek.eu 5 | for Bastl Instruments http://www.bastl-instruments.com/ 6 | based on Mozzi Library http://sensorium.github.io/Mozzi/ 7 | 8 | This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License. 9 | To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/deed.en_US. 10 | ###############***************############### 11 | 12 | 13 | Bastl library for Arduino includes utilities for joining the Mozzi library, 14 | includes necessary files to make the source code compile for Bastl Instruments softwares. 15 | 16 | As Examples included in the library you find the softwares that would run on Trinity synth. 17 | Currently there are MONO FM synth, POLY synth, DRUM and SQNCR. 18 | 19 | Note: the examples might not be the latest versions of these softwares. 20 | Please check their own repositories to get the latest versions. 21 | 22 | To install the Bastl library download the repository (link on the left), 23 | unpack it, rename folder name simply to "bastl" and copy it to "libraries" 24 | folder of your Arduino IDE. You also need to install the Mozzi and the 25 | MIDI library for Arduino. 26 | 27 | For more information about uploading software to Trinity see: 28 | http://www.instructables.com/id/Upload-new-software-to-Trinity-using-Arduino-Jak-n/ 29 | 30 | 31 | Bastl Instruments 32 | 33 | is new brand for electronic hand-made musical instrument which continues the instruments 34 | tradition set up by Standuino. We are the same people and we believe that by focusing on 35 | musical instruments only we are able to achieve higher quality and innovation. 36 | The word Bastl refers very often to DIY electronics in Czech language, but also includes 37 | different forms of funny DIY. 38 | 39 | For more information go to www.bastl-instruments.com 40 | 41 | Trinity 42 | 43 | is open musical instrument bringing the power of digital instruments and their development 44 | to wider Bastl public. It runs Atmega 328 chip reprogrammable by Arduino IDE and ready 45 | to run Mozzi library. 46 | 47 | Trinity is open for any sort of hacks, and we will document them and make instructables 48 | for them. We are hoping to also implement some of the future hacks into the official 49 | Bastl softwares. You can hack the existing softwares or start your own synth software 50 | from scratch using the Mozzi library to output sound. Because Trinity is based on Arduino 51 | you can use the whole world of it to interface literally anything with it. It is hackable 52 | in hardware so you can connect sensors or motors to it or sync it to anything. 53 | The softwares and examples are written in structured form so they read and change 54 | them easily. -------------------------------------------------------------------------------- /FiFoBuffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FiFoBuffer.h 3 | * 4 | * Created on: 10.11.2014 5 | * Author: user 6 | */ 7 | 8 | #ifndef FIFOBUFFER_H_ 9 | #define FIFOBUFFER_H_ 10 | 11 | #include 12 | 13 | /*** FIFOBuffer *** 14 | * This class represents a first-in-first-out type buffer in ring structure 15 | * As template arguments you have to provide its size and the datatype you want to store 16 | */ 17 | 18 | template 19 | class FiFoBuffer { 20 | public: 21 | 22 | FiFoBuffer(): 23 | head(0), 24 | tail(0), 25 | fillCount(0) 26 | {} 27 | 28 | // Add a new entry to the buffer 29 | // returns 1 on success and 0 on full buffer 30 | bool add(const type&); 31 | 32 | // Get the oldest entry in the buffer 33 | // returns 1 on success and 0 on empty buffer 34 | bool get(type&); 35 | 36 | // Read the oldest value without deleting it from the buffer 37 | // returns 1 on success and 0 on empty buffer 38 | bool peek(type&); 39 | 40 | // Check if buffer is full 41 | bool isFull(); 42 | 43 | // Check if buffer is empty 44 | bool isEmpty(); 45 | 46 | // get the number of entries in the buffer 47 | uint8_t getfillCount() { return fillCount;} 48 | 49 | // get direct Pointer to ring Buffer 50 | type* getPointer() {return buffer;} 51 | 52 | private: 53 | uint8_t head; 54 | uint8_t tail; 55 | uint8_t fillCount; 56 | 57 | type buffer[size]; 58 | 59 | // increment position with wrapping on end of buffer 60 | void incrementPos(uint8_t& pos); 61 | 62 | }; 63 | 64 | template 65 | void FiFoBuffer::incrementPos(uint8_t& pos) { 66 | pos++; 67 | if (pos == size) pos = 0; 68 | } 69 | 70 | template 71 | bool FiFoBuffer::add(const type& val) { 72 | 73 | if (isFull()) return false; 74 | 75 | buffer[head] = val; 76 | incrementPos(head); 77 | fillCount++; 78 | 79 | return true; 80 | } 81 | 82 | template 83 | bool FiFoBuffer::get(type& val) { 84 | 85 | if (isEmpty()) return false; 86 | 87 | val = buffer[tail]; 88 | incrementPos(tail); 89 | fillCount--; 90 | 91 | return true; 92 | } 93 | 94 | template 95 | bool FiFoBuffer::peek(type& val) { 96 | 97 | if (isEmpty()) return false; 98 | 99 | val = buffer[tail]; 100 | return true; 101 | } 102 | 103 | template 104 | bool FiFoBuffer::isEmpty() { 105 | return (fillCount == 0); 106 | } 107 | 108 | template 109 | bool FiFoBuffer::isFull() { 110 | return (fillCount == size); 111 | } 112 | 113 | 114 | 115 | #endif /* FIFOBUFFER_H_ */ 116 | -------------------------------------------------------------------------------- /movingAverage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * movingAverage.h 3 | * 4 | * Created on: 13.11.2014 5 | * Author: user 6 | */ 7 | 8 | #ifndef MOVINGAVERAGE_H_ 9 | #define MOVINGAVERAGE_H_ 10 | 11 | // A linear Moving Average Class 12 | // 13 | // the size of the buffer is passed in the constructor 14 | // datatype is set by a template parameter 15 | // 16 | // Values are weightened by index*(255-(255/size)) 17 | // 18 | // works only for uint8_t and uint16_t! 19 | 20 | template 21 | class MovingAverageLinear { 22 | public: 23 | 24 | // construct an object with the given buffer size 25 | MovingAverageLinear(uint8_t size); 26 | 27 | ~MovingAverageLinear(); 28 | 29 | // add another value to the buffer 30 | void add(type value); 31 | 32 | // calculate current average of all elements in buffer 33 | type getAverage(); 34 | 35 | // delete all elements from buffer but set a value that is returned as average 36 | void clear(); 37 | 38 | // returns the number of valid elements in the buffer 39 | uint8_t getFillCount() { return fillCount;} 40 | 41 | // individual access to buffer elements 42 | type operator[](uint8_t index) {return values[index];} 43 | 44 | private: 45 | bool needUpdate; 46 | type average; 47 | type* values; 48 | uint8_t size; 49 | uint8_t fillCount; 50 | uint8_t linearDecrease; 51 | }; 52 | 53 | 54 | template 55 | MovingAverageLinear::MovingAverageLinear(uint8_t size) { 56 | values = new type[size]; 57 | this->size = size; 58 | clear(); 59 | linearDecrease = 255/(size); 60 | } 61 | 62 | template 63 | MovingAverageLinear::~MovingAverageLinear() { 64 | if (values != 0) delete values; 65 | } 66 | 67 | template 68 | void MovingAverageLinear::clear() { 69 | fillCount = 0; 70 | } 71 | 72 | template 73 | void MovingAverageLinear::add(type value) { 74 | 75 | // shift all one back 76 | for (uint8_t index=fillCount; index>=1; index--) { 77 | values[index] = values[index-1]; 78 | } 79 | 80 | // add current value at front 81 | values[0] = value; 82 | 83 | // update status 84 | if (fillCount 89 | type MovingAverageLinear::getAverage() { 90 | 91 | // calculate new average if needed 92 | if (needUpdate && fillCount) { 93 | uint32_t tmpVal = 0; 94 | uint16_t tmpWeight = 0; 95 | for (uint8_t index=0; index 12 | 13 | // namespace to quickly write data to one shift register 14 | // 15 | // in order to use these functions, you need to define the three pins that should be use to shift out the data 16 | // example: 17 | // #define SHIFTREGISTER_SER D,5 18 | // #define SHIFTREGISTER_RCK D,6 19 | // #define SHIFTREGISTER_SRCK D,7 20 | // you have to place those defines BEFORE you include this header file! 21 | // 22 | // shifting out a byte takes ~25us 23 | 24 | 25 | #ifdef SHIFTREGISTER_SER 26 | #ifdef SHIFTREGISTER_RCK 27 | #ifdef SHIFTREGISTER_SRCK 28 | 29 | namespace shiftRegFast { 30 | 31 | enum BitOrder {LSB_FIRST,MSB_FIRST}; 32 | 33 | // initialize pins 34 | // call this function before shifting out data! 35 | inline void setup() { 36 | 37 | //set pins to output mode 38 | bit_dir_outp(SHIFTREGISTER_SER); 39 | bit_dir_outp(SHIFTREGISTER_SRCK); 40 | bit_dir_outp(SHIFTREGISTER_RCK); 41 | 42 | //initialize clocks to low 43 | bit_clear(SHIFTREGISTER_SRCK); 44 | bit_clear(SHIFTREGISTER_RCK); 45 | } 46 | 47 | // pulse the serial clock to shift storage registers and place vaule from SER to first storage register 48 | inline void serClkIn() { 49 | bit_set(SHIFTREGISTER_SRCK); 50 | bit_clear(SHIFTREGISTER_SRCK); 51 | } 52 | 53 | // pulse the latch pin to copy data from storage register to output 54 | inline void enableOutput() { 55 | bit_set(SHIFTREGISTER_RCK); 56 | bit_clear(SHIFTREGISTER_RCK); 57 | } 58 | 59 | // set the data pin to the given value 60 | inline void setDataBit(bool value) { 61 | if (value) bit_set(SHIFTREGISTER_SER); 62 | else bit_clear(SHIFTREGISTER_SER); 63 | } 64 | 65 | // send out a byte 66 | inline void write_8bit(uint8_t byte, shiftRegFast::BitOrder order = LSB_FIRST) { 67 | if (order == LSB_FIRST) { 68 | for (uint8_t index = 0; index < 8; index++) { 69 | setDataBit(bitRead(byte,index)); 70 | serClkIn(); 71 | } 72 | } else { 73 | for (int8_t index = 7; index >=0; index--) { 74 | setDataBit(bitRead(byte,index)); 75 | serClkIn(); 76 | } 77 | } 78 | } 79 | 80 | // send out an integer 81 | inline void write_16bit(uint16_t integer, shiftRegFast::BitOrder order=LSB_FIRST) { 82 | if (order == LSB_FIRST) { 83 | for (uint8_t index = 0; index < 16; index++) { 84 | setDataBit(bitRead(integer,index)); 85 | serClkIn(); 86 | } 87 | } else { 88 | for (int8_t index = 15; index>=0; index--) { 89 | setDataBit(bitRead(integer,index)); 90 | serClkIn(); 91 | } 92 | } 93 | } 94 | } 95 | 96 | #endif 97 | #endif 98 | #endif 99 | 100 | 101 | #endif /* SHIFTREGISTERFAST_H_ */ 102 | -------------------------------------------------------------------------------- /Arpeggiator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Arpeggiator.h 3 | * 4 | * Created on: Apr 11, 2015 5 | * Author: Martin Baar 6 | */ 7 | 8 | #ifndef ARPEGGIATOR_H_ 9 | #define ARPEGGIATOR_H_ 10 | 11 | #define ARPEGGIATOR_MAX_VALUES 20 12 | 13 | /** 14 | * Class to generate arpeggiato from set of notes 15 | */ 16 | class Arpeggiator { 17 | 18 | public: 19 | 20 | /** Enumeration of possible arpeggio flows */ 21 | enum ArpeggioAlgorithm {UP, DOWN, UP_DOWN, SORTED, RANDOM}; 22 | 23 | /** Default constructor */ 24 | Arpeggiator(); 25 | 26 | /** 27 | * Method to add note to arpeggiator 28 | * @param note note to add 29 | * @return true if add successfully otherwise false (buffer full or note already there) 30 | */ 31 | bool addNote(unsigned char note); 32 | 33 | /** 34 | * Method to remove note from arpeggiator 35 | * @param note note to remove 36 | * @return true if removed successfully otherwise false (note not there) 37 | */ 38 | bool removeNote(unsigned char note); 39 | 40 | /** 41 | * To get next note to play 42 | * @param note return argument filled with next note to play if any exists otherwise kept unchanged 43 | * @return true if there is some note to be played as next 44 | */ 45 | bool getNextNote(unsigned char & note); 46 | 47 | //Setters 48 | 49 | /** 50 | * Sets the algorithm arpeggiator shall use to generate sequence 51 | * @param algorithm algorithm to be used 52 | */ 53 | void setAlgorithm(ArpeggioAlgorithm algorithm); 54 | 55 | /** 56 | * Sets arpeggio sequence length (number of last added steps that will be played) 57 | * @param size window size to be set 58 | */ 59 | void setWindowSize(unsigned char size); 60 | 61 | //Controllers 62 | 63 | /** resets arpeggiator to be played from beginning */ 64 | void reset(); 65 | 66 | /** clears all arpeggiator notes and resets it */ 67 | void clear(); 68 | 69 | private: 70 | 71 | ArpeggioAlgorithm algorithm_; 72 | unsigned char windowSize_; 73 | unsigned char notes_[ARPEGGIATOR_MAX_VALUES]; 74 | unsigned char sortedNotes_[ARPEGGIATOR_MAX_VALUES]; 75 | unsigned char count_; 76 | bool started_; 77 | unsigned char currentIndex_; 78 | bool upDownGoingUp_; 79 | bool removeNoteAfterGettingNext_; 80 | 81 | bool findValue(unsigned char value, unsigned char * array, unsigned char & index); 82 | unsigned char getNextIndex(); 83 | void fillSorted(); 84 | }; 85 | 86 | inline void Arpeggiator::setAlgorithm(Arpeggiator::ArpeggioAlgorithm algorithm) { 87 | algorithm_ = algorithm; 88 | upDownGoingUp_ = true; 89 | } 90 | 91 | inline void Arpeggiator::setWindowSize(unsigned char size) { 92 | windowSize_ = size; 93 | } 94 | 95 | inline void Arpeggiator::reset() { 96 | started_ = false; 97 | } 98 | 99 | inline void Arpeggiator::clear() { 100 | count_ = 0; 101 | reset(); 102 | } 103 | 104 | 105 | #endif /* ARPEGGIATOR_H_ */ 106 | -------------------------------------------------------------------------------- /interpolatingBuffer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * interpolatingBuffer.cpp 3 | 4 | * 5 | * Created on: Jan 28, 2015 6 | * Author: dasvaclav 7 | */ 8 | #include "interpolatingBuffer.h" 9 | #include 10 | 11 | //#include 12 | 13 | #include 14 | //#include "mapping.h" 15 | Line linear[6]; 16 | /* 17 | interpolatingBuffer::interpolatingBuffer(){ 18 | 19 | } 20 | */ 21 | void interpolatingBuffer::init(uint8_t channel){ 22 | intCh=channel; 23 | } 24 | void interpolatingBuffer::sync(){ 25 | 26 | } 27 | 28 | uint8_t interpolatingBuffer::getCurrentValue(){ 29 | if(interpolate){ 30 | if(interpolatedSteps=periodInSteps){ 47 | smallSteps=0; 48 | if(step<31){ 49 | step++; 50 | } 51 | else{ 52 | step=0; 53 | } 54 | if(!interpolate){ 55 | if(!loopState) addRandomStep(); //? 56 | else rotateBuffer(); 57 | } 58 | } 59 | 60 | smoothSteps++; 61 | //if(smoothingAmount>127){ 62 | uint16_t smoothingSkip=map(smoothingAmount,0,2047,0,periodInSteps); 63 | if(smoothSteps>=smoothingSkip){ 64 | smoothSteps=0; 65 | addSmoothStep(buffer[0]); 66 | } 67 | 68 | } 69 | 70 | void interpolatingBuffer::setStep(uint8_t _step){ 71 | interpolateStep=_step; 72 | interpolateInSteps=map(interpolateAmount,0,255,1,periodInSteps); 73 | if(interpolate){ 74 | if(_step<31){ 75 | linear[intCh].set(buffer[_step],buffer[_step+1],interpolateInSteps); 76 | } 77 | else{ 78 | linear[intCh].set(buffer[_step],buffer[0],interpolateInSteps); 79 | } 80 | } 81 | interpolatedSteps=0; 82 | } 83 | void interpolatingBuffer::addRandomStep(){ 84 | rotateBuffer(); 85 | int16_t randomNumber=random(0,64)-31+buffer[1]; 86 | if(randomNumber>255) randomNumber=255; 87 | if(randomNumber<0) randomNumber=0; 88 | buffer[0]=randomNumber; 89 | } 90 | 91 | void interpolatingBuffer::addSmoothStep(uint8_t _value){ 92 | rotateSmoothBuffer(); 93 | smoothBuffer[0]=_value; 94 | } 95 | 96 | void interpolatingBuffer::rotateBuffer(){ 97 | uint8_t temp=buffer[31]; 98 | for(uint8_t i=31;i>0;i--){ 99 | buffer[i]=buffer[i-1]; 100 | } 101 | buffer[0]=temp; 102 | } 103 | 104 | void interpolatingBuffer::rotateSmoothBuffer(){ 105 | uint8_t temp=smoothBuffer[31]; 106 | for(uint8_t i=31;i>0;i--){ 107 | smoothBuffer[i]=smoothBuffer[i-1]; 108 | } 109 | smoothBuffer[0]=temp; 110 | } 111 | uint8_t interpolatingBuffer::calculateSmoothAverage(){ 112 | uint16_t sum=0; 113 | for(int i=0;i<32;i++){ 114 | sum+=smoothBuffer[i]; 115 | } 116 | return sum/32; 117 | } 118 | 119 | -------------------------------------------------------------------------------- /MIDInoteBuffer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIDInoteBuffer.cpp 3 | 4 | * 5 | * Created on: Jan 28, 2015 6 | * Author: dasvaclav 7 | */ 8 | #include "MIDInoteBuffer.h" 9 | #include 10 | 11 | #define LEFT_SHIFT 0 12 | #define RIGHT_SHIFT 1 13 | void MIDInoteBuffer::init(){ 14 | clearBuffers(); 15 | } 16 | void MIDInoteBuffer::orderBuffer(){ 17 | for(int j=0;j orderedBuffer[j-1] ) nextOne=midiBuffer[i]; 28 | } 29 | orderedBuffer[j]=nextOne; 30 | } 31 | } 32 | void MIDInoteBuffer::setPolyphony(uint8_t _polyphony){ 33 | polyphony=_polyphony; 34 | } 35 | uint8_t MIDInoteBuffer::getNoteToBePlayedAgain(){ 36 | return midiBuffer[polyphony]; 37 | } 38 | uint8_t MIDInoteBuffer::getVelocityOfNoteToBePlayedAgain(){ 39 | return velocityBuffer[polyphony]; 40 | } 41 | uint8_t MIDInoteBuffer::getNumberOfNotesInBuffer(){ 42 | return notesInBuffer; 43 | } 44 | uint8_t MIDInoteBuffer::getNoteFromBuffer(uint8_t _note){ 45 | return midiBuffer[_note]; 46 | } 47 | uint8_t MIDInoteBuffer::getVelocityFromBuffer(uint8_t _note){ 48 | return velocityBuffer[_note]; 49 | } 50 | uint8_t MIDInoteBuffer::getNoteFromOrderedBuffer(uint8_t _note){ 51 | return orderedBuffer[_note]; 52 | } 53 | void MIDInoteBuffer::clearBuffers(){ 54 | for(int i=0;ifrom;i--){ 70 | midiBuffer[i]=midiBuffer[i-1]; 71 | velocityBuffer[i]=velocityBuffer[i-1]; 72 | } 73 | } 74 | } 75 | uint8_t MIDInoteBuffer::findNoteInBuffer(uint8_t note){ 76 | for(int i=0;i0){ 84 | uint8_t position=findNoteInBuffer(note); 85 | if(position!=255) shiftBuffer(LEFT_SHIFT,position),notesInBuffer--; 86 | } 87 | if(notesInBuffer>=polyphony) return 1; 88 | else return 0; 89 | } 90 | void MIDInoteBuffer::addNoteToBuffer(uint8_t _note, uint8_t _velocity){ 91 | 92 | removeNoteFromBuffer(_note); 93 | shiftBuffer(RIGHT_SHIFT,0); 94 | 95 | if(notesInBuffer> 8); 44 | data[8] = triggerLength_; 45 | data[9] = patternMomentary_ ? 1 : 0; 46 | data[10] = swingValue_; 47 | } 48 | 49 | void PlayerSettings::loadFromByteArray(unsigned char * data) { 50 | drumInstrumentEventTypes_ = data[0]; 51 | instrumentStatuses_ = data[1]; 52 | currentPattern_ = data[2]; 53 | recordQunatizationType_ = (data[3] > 4) ? _1_64 :(QuantizationType)(data[3]); 54 | multiplication_ = (data[4] > 4) ? _8 :(MultiplicationType)(data[4]); 55 | playerMode_ = (data[5] > 1) ? MASTER : (PlayerMode)(data[5]); 56 | bpm_ = data[6]; 57 | bpm_ += (((unsigned int)data[7]) << 8); 58 | triggerLength_ = data[8]; 59 | patternMomentary_ = data[9]& 1 != 0; 60 | swingValue_ = data[10]; 61 | 62 | // Here comes the value validation: 63 | swingValue_ = (swingValue_ > 55) ? 0 : swingValue_; 64 | triggerLength_ = (triggerLength_ > 7) ? 0 : triggerLength_; 65 | bpm_ = (bpm_ > 500) ? 120 : bpm_; 66 | currentPattern_ = (currentPattern_ > 64) ? 0 : currentPattern_; 67 | instrumentStatuses_ = (instrumentStatuses_ > 64) ? 0 : instrumentStatuses_; 68 | drumInstrumentEventTypes_ = (drumInstrumentEventTypes_ > 64) ? 0 : drumInstrumentEventTypes_; 69 | 70 | 71 | resetManipulatedPatterns(); 72 | } 73 | 74 | unsigned char PlayerSettings::getRecordQuantizationSize() { 75 | unsigned char quantizationRate = 1; 76 | for (unsigned char powNumber = 0; powNumber < (unsigned char)recordQunatizationType_; powNumber++) { 77 | quantizationRate *= 2; 78 | } 79 | return quantizationRate; 80 | 81 | } 82 | -------------------------------------------------------------------------------- /lfoExtended.h: -------------------------------------------------------------------------------- 1 | /* 2 | * lfoExtended.h 3 | * 4 | * Created on: 31.07.2014 5 | * Author: user 6 | */ 7 | 8 | #ifndef LFOEXTENDED_H_ 9 | #define LFOEXTENDED_H_ 10 | 11 | 12 | #include "basic.h" 13 | 14 | 15 | #ifdef TESTING 16 | #include 17 | #endif 18 | 19 | 20 | enum LFOBasicWaveform {SAW,TRIANGLE,RANDOM}; 21 | enum LFOThresholdType {OVERFLOW,FOLDING}; 22 | 23 | 24 | 25 | class lfoExtended { 26 | 27 | public: 28 | // Initialize all settings 29 | void init(uint16_t bastlCycleFrequency); 30 | 31 | 32 | public: 33 | // set the base frequency of the LFO by its period length 34 | // due to fixed point precision, the actual waveform frequency will be: 35 | // f_out = f_in * floor(floor(2^16 + p/2)/p) / 2^16 ~ f_in/p 36 | // minimum period: 2 37 | // maximum period: 65535 38 | void setBastlCyclesPerPeriod(uint16_t bastlCyclesPerPeriod); 39 | 40 | // set waveform to given step number at a given time 41 | void setToStep(uint8_t stepNumber, uint16_t time); 42 | 43 | // set the shape basic waveform 44 | // TRIANGLE, SAW or RANDOM 45 | void setWaveform(LFOBasicWaveform waveform); 46 | 47 | // the output value is XORed with xorBits 48 | void setXOR(uint8_t xorBits); 49 | 50 | // set the output to zero if any of the flopBits are set in the current step number 51 | // to create less advanced patterns, set flopBits to (1< 6 | #define minimum(a,b) ((a)<(b)?(a):(b)) 7 | 8 | // This object quantizes time in uints of stepLength and returns the step number modulo numbsteps 9 | // ((time (- offset)) / stepLength) % numbSteps 10 | // as time is overflowing, this object needs to work on time differences, which creates the nescessity 11 | // for it to keep a memory of the current step time 12 | // This has the disadvantage (over 'direct formula') that you cannot jump back in time but the advantage that 13 | // tempo changes are being handled correctly with no effort 14 | // The maximum inaccuracy defines how many time units before a step a call to getClosestStep() may map to that step 15 | 16 | 17 | 18 | class Stepper { 19 | public: 20 | 21 | // initialize an instance, setting its essential properties 22 | void init(uint16_t stepLength, uint8_t numbSteps, uint8_t maxInaccuracy = 255) { 23 | setStepLength(stepLength); 24 | setNumbSteps(numbSteps); 25 | this-> maxInaccuracy = maxInaccuracy; 26 | } 27 | 28 | // change the time difference between two steps 29 | void setStepLength(uint16_t stepLength) { 30 | if (stepLength == 0) return; 31 | 32 | this->stepLength = stepLength; 33 | } 34 | 35 | // set the number of steps after which the step number will wrap to zero 36 | void setNumbSteps(uint8_t numbSteps) { 37 | if (numbSteps == 0) return; 38 | 39 | this->numbSteps = numbSteps; 40 | 41 | // map current position to changed period length 42 | while (lastStep >= numbSteps) { 43 | lastStep -= numbSteps; 44 | } 45 | } 46 | 47 | // set the playhead to a given step number at a given time 48 | void setToStep(uint16_t time, uint8_t step) { 49 | lastTime = time; 50 | lastStep = step; 51 | timeFromLastStep = 0; 52 | } 53 | 54 | // proceed to the given point in time and return the last step number 55 | uint8_t getCurrentStep(uint16_t time) { 56 | 57 | movePosition(time); 58 | return lastStep; 59 | } 60 | 61 | // proceed to the given point in time 62 | // return the step number that is closest (can be last or previous one) 63 | uint8_t getClosestStep(uint16_t time) { 64 | 65 | movePosition(time); 66 | 67 | uint8_t returnVal = lastStep; 68 | if ((stepLength-timeFromLastStep) < minimum(stepLength/2,maxInaccuracy)) { 69 | incStep(returnVal); 70 | } 71 | 72 | return returnVal; 73 | 74 | } 75 | 76 | private: 77 | 78 | // proceed to the given point in time 79 | void movePosition(uint16_t time) { 80 | 81 | uint16_t timeDiff = timeFromLastStep + (time-lastTime); 82 | lastTime = time; 83 | 84 | while (timeDiff>=stepLength) { 85 | timeDiff -= stepLength; 86 | incStep(lastStep); 87 | } 88 | 89 | timeFromLastStep = timeDiff; 90 | } 91 | 92 | // increment step number with wrapping 93 | inline void incStep(uint8_t& val) { 94 | val++; 95 | if (val >= numbSteps) val=0; 96 | } 97 | 98 | uint8_t maxInaccuracy; // the maximum number of time units a call to getClosestStep() maps forward in time 99 | 100 | uint8_t numbSteps; // the number of steps after which the step number wraps to zero 101 | uint16_t stepLength; // the number of time units between two steps 102 | 103 | uint16_t timeFromLastStep; // the number of time units the current position is ahead of a step 104 | uint16_t lastTime; // the last time this instance was called 105 | uint8_t lastStep; // the number of the last complete step 106 | 107 | }; 108 | 109 | 110 | 111 | #endif /* STEPPER_H_ */ 112 | -------------------------------------------------------------------------------- /simpleSerialDecoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * simpleSerialDecoder.h 3 | * 4 | * Created on: Jan 23, 2015 5 | * Author: dasvaclav 6 | */ 7 | 8 | #ifndef SIMPLESERIALDECODER_H_ 9 | #define SIMPLESERIALDECODER_H_ 10 | 11 | #include 12 | #include 13 | class simpleSerialDecoder { 14 | 15 | public: 16 | void init(uint16_t baudrate); 17 | void update(); 18 | void sendPairMessage(); 19 | 20 | void sendClock(uint8_t _number); 21 | void sendStep(uint8_t _number); 22 | void sendGate(uint8_t _number); 23 | void sendTrigger(uint8_t _number); 24 | void sendStart(uint8_t _number); 25 | void sendStop(uint8_t _number); 26 | void sendRestart(uint8_t _number); 27 | void sendSelect(uint8_t _number); 28 | 29 | void sendChannelTrigger(uint8_t _channel, uint8_t _number); 30 | void sendChannelGate(uint8_t _channel, uint8_t _number); 31 | void sendChannelCV(uint8_t _channel, uint8_t _number); 32 | void sendChannelInterpolateFrom(uint8_t _channel, uint8_t _number); 33 | void sendChannelInterpolateTo(uint8_t _channel, uint8_t _number); 34 | void sendChannelInterpolate(uint8_t _channel, uint8_t _number); 35 | void sendChannelMode(uint8_t _channel, uint8_t _number); 36 | 37 | void sendChannelValue(uint8_t _channel, uint8_t _value, uint8_t _number); 38 | 39 | void attachClockCallback(void(*clockInCallback)(uint8_t number)); 40 | void attachStepCallback(void(*stepCallback)(uint8_t number)); 41 | void attachGateCallback(void(*gateCallback)(uint8_t number)); 42 | void attachTriggerCallback(void(*triggerCallback)(uint8_t number)); 43 | void attachStartCallback(void(*startCallback)(uint8_t number)); 44 | void attachStopCallback(void(*stopCallback)(uint8_t number)); 45 | void attachRestartCallback(void(*restartCallback)(uint8_t number)); 46 | void attachSelectCallback(void(*selectCallback)(uint8_t number)); 47 | void attachChannelTriggerCallback(void(*channelTriggerCallback)(uint8_t channel, uint8_t number)); 48 | void attachChannelGateCallback(void(*channelGateCallback)(uint8_t channel, uint8_t number)); 49 | void attachChannelCVCallback(void(*channelCVCallback)(uint8_t channel, uint8_t number)); 50 | void attachChannelInterpolateFromCallback(void(*channelInterpolateFromCallback)(uint8_t channel, uint8_t number)); 51 | void attachChannelInterpolateToCallback(void(*channelInterpolateToCallback)(uint8_t channel, uint8_t number)); 52 | void attachChannelInterpolateCallback(void(*channelInterpolateCallback)(uint8_t channel, uint8_t number)); 53 | void attachChannelModeCallback(void(*channelModeCallback)(uint8_t channel, uint8_t number)); 54 | void attachChannelValueCallback(void(*channelValueCallback)(uint8_t channel, uint8_t value, uint8_t number)); 55 | 56 | private: 57 | uint8_t _type; 58 | uint8_t _value; 59 | void (*clockInCallback)(uint8_t number); 60 | void (*stepCallback)(uint8_t number); 61 | void (*gateCallback)(uint8_t number); 62 | void (*triggerCallback)(uint8_t number); 63 | void (*startCallback)(uint8_t number); 64 | void (*stopCallback)(uint8_t number); 65 | void (*restartCallback)(uint8_t number); 66 | void (*selectCallback)(uint8_t number); 67 | void (*channelTriggerCallback)(uint8_t channel, uint8_t number); 68 | void (*channelGateCallback)(uint8_t channel, uint8_t number); 69 | void (*channelCVCallback)(uint8_t channel, uint8_t number); 70 | void (*channelInterpolateFromCallback)(uint8_t channel, uint8_t number); 71 | void (*channelInterpolateToCallback)(uint8_t channel, uint8_t number); 72 | void (*channelInterpolateCallback)(uint8_t channel, uint8_t number); 73 | void (*channelModeCallback)(uint8_t channel, uint8_t number); 74 | void (*channelValueCallback)(uint8_t channel, uint8_t value, uint8_t number); 75 | 76 | 77 | }; 78 | 79 | 80 | 81 | 82 | #endif /* SIMPLESERIALDECODER_H_ */ 83 | -------------------------------------------------------------------------------- /expADSR.h: -------------------------------------------------------------------------------- 1 | // 2 | // ADRS.h 3 | // 4 | // Created by Nigel Redmon on 12/18/12. 5 | // EarLevel Engineering: earlevel.com 6 | // Copyright 2012 Nigel Redmon 7 | // 8 | // For a complete explanation of the ADSR envelope generator and code, 9 | // read the series of articles by the author, starting here: 10 | // http://www.earlevel.com/main/2013/06/01/envelope-generators/ 11 | // 12 | // License: 13 | // 14 | // This source code is provided as is, without warranty. 15 | // You may copy and distribute verbatim copies of this document. 16 | // You may modify and use this source code to create binary code for your own purposes, free or commercial. 17 | // 18 | 19 | #ifndef EXP_ADRS_h 20 | #define EXP_ADRS_h 21 | 22 | 23 | class ADSR { 24 | public: 25 | ADSR(void); 26 | ~ADSR(void); 27 | float process(void); 28 | float getOutput(void); 29 | int getState(void); 30 | void gate(int on); 31 | void setAttackRate(float rate); 32 | void setHoldRate(long rate){ hold_value=rate;}; 33 | void setDecayRate(float rate); 34 | void setReleaseRate(float rate); 35 | void setSustainLevel(float level); 36 | void setTargetRatioA(float targetRatio); 37 | void setTargetRatioDR(float targetRatio); 38 | void reset(void); 39 | void setHold(bool _hold){ hold=_hold;}; 40 | void sync(); 41 | void setLoop(bool _loop){ looping=_loop;}; 42 | 43 | enum envState { 44 | env_idle = 0, 45 | env_attack, 46 | env_decay, 47 | env_sustain, 48 | env_release, 49 | env_hold 50 | }; 51 | 52 | protected: 53 | bool hold; 54 | bool looping; 55 | int state; 56 | long hold_count; 57 | long hold_value; 58 | float output; 59 | float attackRate; 60 | float decayRate; 61 | float releaseRate; 62 | float attackCoef; 63 | float decayCoef; 64 | float releaseCoef; 65 | float sustainLevel; 66 | float targetRatioA; 67 | float targetRatioDR; 68 | float attackBase; 69 | float decayBase; 70 | float releaseBase; 71 | 72 | float calcCoef(float rate, float targetRatio); 73 | }; 74 | 75 | inline float ADSR::process() { 76 | switch (state) { 77 | case env_hold: 78 | hold_count++; 79 | if(hold_count>=hold_value){ 80 | hold_count=0; 81 | if(looping) state = env_release; 82 | else state = env_decay; 83 | } 84 | 85 | output = 1.0; 86 | break; 87 | case env_idle: 88 | if(looping){ 89 | state = env_attack; 90 | } 91 | break; 92 | case env_attack: 93 | output = attackBase + output * attackCoef; 94 | if (output >= 1.0) { 95 | output = 1.0; 96 | if(hold) state = env_hold, hold_count=0; 97 | else if(looping) state = env_release; 98 | else state = env_decay; 99 | } 100 | break; 101 | case env_decay: 102 | output = decayBase + output * decayCoef; 103 | if (output <= sustainLevel) { 104 | output = sustainLevel; 105 | state = env_sustain; 106 | } 107 | break; 108 | case env_sustain: 109 | break; 110 | case env_release: 111 | output = releaseBase + output * releaseCoef; 112 | if (output <= 0.0) { 113 | output = 0.0; 114 | if(looping) state = env_attack; 115 | else state = env_idle; 116 | } 117 | } 118 | return output; 119 | } 120 | 121 | inline void ADSR::gate(int gate) { 122 | if (gate) 123 | state = env_attack; 124 | else if (state != env_idle) 125 | state = env_release; 126 | } 127 | 128 | inline int ADSR::getState() { 129 | return state; 130 | } 131 | 132 | inline void ADSR::reset() { 133 | state = env_idle; 134 | output = 0.0; 135 | } 136 | 137 | inline float ADSR::getOutput() { 138 | return output; 139 | } 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /stateHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef STATEHANDLER_H 2 | #define STATEHANDLER_H 3 | 4 | 5 | #include 6 | 7 | 8 | ////////////////// EXAMPLE ////////////////////// 9 | /* 10 | 11 | enum stateNames {START,SHIFT}; 12 | 13 | STATEFUNCS 14 | 15 | STATE(START) 16 | 17 | ON_ENTER 18 | 19 | ALWAYS 20 | 21 | ON_EVENT 22 | 23 | EVENTCHECK(BTN_DOWN,ShiftButton) 24 | CHANGE_STATE(SHIFT); 25 | END_EVENTCHECK 26 | 27 | ON_EXIT 28 | 29 | END_STATE 30 | 31 | STATE(SHIFT) 32 | 33 | ON_ENTER 34 | 35 | ALWAYS 36 | 37 | ON_EVENT 38 | 39 | EVENTCHECK(BTN_UP,ShiftButton) 40 | CHANGE_STATE(START); 41 | END_EVENTCHECK 42 | 43 | ON_EXIT 44 | 45 | END_STATE 46 | 47 | END_STATEFUNCS 48 | 49 | */ 50 | 51 | 52 | 53 | ////// Marcos for implicitly defining run() which 54 | ////// processes the current state 55 | //////////////////////////////////////////////// 56 | #define STATEFUNCS uint8_t states::activeState = 0;\ 57 | bool states::newState = true;\ 58 | bool states::eventProcessed = true;\ 59 | hardwareEvent states::lastEvent;\ 60 | void states::run() { 61 | 62 | #define ANYSTATE 63 | #define ANYSTATE_ENTER if(newState) { 64 | #define ANYSTATE_EVENT } if (!eventProcessed) { 65 | #define END_ANYSTATE } switch (activeState) { 66 | 67 | #define STATE(N) case N: 68 | #define ON_ENTER if (newState) { // code that is executed everytime this state is run for the first time 69 | #define ALWAYS newState = false;} // code that is executed everytime this state is active 70 | #define ON_EVENT if (!eventProcessed) { // code that is executed when there is a new event 71 | #define ON_EXIT eventProcessed = true;}if (newState) { // code that is executed when this state is run for the last time 72 | 73 | #define END_STATE }break; 74 | #define END_STATEFUNCS default: break; }} 75 | 76 | #define CHANGE_STATE(N) activeState = N; newState = true; // switch to different state in next run 77 | #define RERUN_STATE newState = true; eventProcessed = true; return; // re-renter the current state in next run. 78 | // In ANYSTATE, this will NOT enter the real state! 79 | 80 | 81 | 82 | ////// Macros for analysing the last read event 83 | //////////////////////////////////////////////// 84 | #define DONT_CARE_NUMBER lastEvent.number 85 | #define THIS_NUMBER lastEvent.number 86 | 87 | // check for type and number 88 | #define EVENTCHECK(...) EVENTCHECK_(__VA_ARGS__) 89 | #define EVENTCHECK_(TY,NU) if((lastEvent.type == IHWLayer::TY) && (lastEvent.number == NU) ) { 90 | #define END_EVENTCHECK } 91 | 92 | // check for type and if number is inside array 93 | // if match has been found it will be written to VAR 94 | #define EVENTCHECK_ARRAY(TY,AR,VAR) if ((lastEvent.type == IHWLayer::TY)) {\ 95 | for (uint8_t VAR = 0; VAR 13 | #endif 14 | 15 | 16 | 17 | 18 | 19 | /* Functionality explained 20 | * 21 | * # A tap cycle consists of a number of taps that occur in approximately 22 | * equal distances 23 | * # Average is taken over the last *averageWidth* tap time DIFFERENCES to calculate tap tempo 24 | * # An active cycle is reset when the relative deviation exceeds a given limit. 25 | * This is considered as a desired tempo change 26 | * # Also absolute limits are needed when no tempo is known yet 27 | * 28 | */ 29 | 30 | 31 | Tapper::Tapper() : historyFillCount(0), 32 | lastTapTime(0), 33 | stepsPerTap_(1), 34 | maxStepLengthInTimeUnits(0), 35 | maxRelativeDeviation(0), 36 | firstOfCycle(true), 37 | makeStep_(0) { 38 | 39 | } 40 | Tapper::~Tapper() { 41 | delete history; 42 | } 43 | 44 | void Tapper::init(uint16_t maxStepLengthInTimeUnits, uint8_t maxRelativeDeviation) 45 | { 46 | this->maxStepLengthInTimeUnits = maxStepLengthInTimeUnits; 47 | this->maxRelativeDeviation = maxRelativeDeviation; 48 | firstOfCycle = true; 49 | setStepsPerTap(1); 50 | } 51 | 52 | void Tapper::addToHistory(uint16_t val) { 53 | historyHead++; 54 | if (historyHead == historyLen) historyHead=0; 55 | 56 | history[historyHead] = val; 57 | 58 | if (historyFillCount < historyLen) historyFillCount++; 59 | 60 | 61 | } 62 | uint16_t Tapper::getAverage() { 63 | 64 | if (historyFillCount == 0) return getLast(); 65 | 66 | uint32_t sum = 0; 67 | 68 | uint8_t pos = historyHead; 69 | 70 | for (uint8_t index=0; index>6); 107 | 108 | if (deviation Restarting cycle\n",thisTapDifference,deviation); 122 | #endif 123 | historyFillCount = 0; 124 | if (resetCallback) resetCallback(tapTime); 125 | } 126 | 127 | } else { 128 | if ((!firstOfCycle) && (thisTapDifference < maxStepLengthInTimeUnits)) { 129 | // insert first tempo 130 | #ifdef TESTING 131 | printf(" Second tap -> adding first tempo to history: %u\n",thisTapDifference); 132 | #endif 133 | addToHistory(thisTapDifference); 134 | } else { 135 | 136 | #ifdef TESTING 137 | printf(" Starting very first tap cyle\n"); 138 | #endif 139 | firstOfCycle = false; 140 | if (resetCallback) resetCallback(tapTime); 141 | } 142 | } 143 | 144 | // always remember last tap time 145 | lastTapTime = tapTime; 146 | 147 | 148 | // call callback 149 | if (makeStep_ != 0) { 150 | #ifdef TESTING 151 | printf("Tapper::tap Sending step command.\n"); 152 | #endif 153 | makeStep_(); 154 | } 155 | 156 | 157 | 158 | 159 | 160 | } 161 | -------------------------------------------------------------------------------- /test/tstRadioButton.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "HWLayerMock.h" 3 | #include "../RadioButtons.h" 4 | //#include "../Switches.h" 5 | #include 6 | 7 | int main( int argc, const char* argv[] ) { 8 | HWLayerMock hw; 9 | unsigned char radioButtons[16] = {0, 2, 4, 6, 8/*first in test*/, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30}; 10 | unsigned char * button = &(radioButtons[4]); 11 | RadioButtons buttons(&hw, button, 6); 12 | unsigned char selectedButton = 0; 13 | 14 | printf("Radio Buttons\n"); 15 | printf("\tTest 1 - Default radio state \t\t%s\n", !buttons.getSelectedButton(selectedButton) ? "OK" : "Error"); 16 | 17 | hw.setButtonState(10, true); 18 | buttons.update(); 19 | printf("\tTest 2 - Radio State after select \t\t%s\n", buttons.getSelectedButton(selectedButton) && selectedButton == 1 ? "OK" : "Error"); 20 | 21 | hw.setButtonState(10, false); 22 | hw.setButtonState(14, true); 23 | buttons.update(); 24 | printf("\tTest 3 - Radio state after select another \t\t%s\n", buttons.getSelectedButton(selectedButton) && selectedButton == 3 ? "OK" : "Error"); 25 | 26 | buttons.update(); 27 | printf("\tTest 4 - Not released button \t\t%s\n", buttons.getSelectedButton(selectedButton) && selectedButton == 3 ? "OK" : "Error"); 28 | 29 | hw.setButtonState(14, false); 30 | buttons.update(); 31 | printf("\tTest 5 - Released button \t\t%s\n", buttons.getSelectedButton(selectedButton) && selectedButton == 3 ? "OK" : "Error"); 32 | 33 | hw.setButtonState(14, true); 34 | buttons.update(); 35 | printf("\tTest 6 - Button pressed again \t\t%s\n", !buttons.getSelectedButton(selectedButton) ? "OK" : "Error"); 36 | 37 | hw.setButtonState(14, false); 38 | buttons.update(); 39 | hw.setButtonState(14, true); 40 | buttons.update(); 41 | printf("\tTest 7 - Button release and pressed again \t\t%s\n", buttons.getSelectedButton(selectedButton) && selectedButton == 3 ? "OK" : "Error"); 42 | 43 | 44 | /*printf("Down activate Switches\n"); 45 | 46 | unsigned char switchesButtons[16] = {0, 2, 4, 6, 8, 10, 12, 14, 16}; 47 | Switches switches; 48 | switches.init(&hw, switchesButtons, 9); 49 | 50 | hw.setButtonState(16, true); 51 | switches.update(); 52 | printf("\tTest 7 - Button pressed \t\t%s\n", switches.getStatus(8) ? "OK" : "Error"); 53 | switches.update(); 54 | printf("\tTest 8 - Button keep pressed \t\t%s\n", switches.getStatus(8) ? "OK" : "Error"); 55 | hw.setButtonState(16, false); 56 | switches.update(); 57 | printf("\tTest 9 - Button released \t\t%s\n", switches.getStatus(8) ? "OK" : "Error"); 58 | hw.setButtonState(16, true); 59 | switches.update(); 60 | printf("\tTest 10 - Button pressed again \t\t%s\n", !switches.getStatus(8) ? "OK" : "Error"); 61 | 62 | switches.setStatus(8, true); 63 | printf("\tTest 11 - Button set externally to pressed \t\t%s\n", switches.getStatus(8) ? "OK" : "Error"); 64 | switches.setStatus(8, false); 65 | printf("\tTest 12 - Button set externally to released \t\t%s\n", !switches.getStatus(8) ? "OK" : "Error"); 66 | 67 | printf("Up activate Switches\n"); 68 | 69 | Switches switches2; 70 | switches2.init(&hw, switchesButtons, 9, IHWLayer::UP); 71 | 72 | hw.setButtonState(16, true); 73 | switches2.update(); 74 | printf("\tTest 7 - Button pressed \t\t%s\n", !switches2.getStatus(8) ? "OK" : "Error"); 75 | switches2.update(); 76 | printf("\tTest 8 - Button keep pressed \t\t%s\n", !switches2.getStatus(8) ? "OK" : "Error"); 77 | hw.setButtonState(16, false); 78 | switches2.update(); 79 | printf("\tTest 9 - Button released \t\t%s\n", switches2.getStatus(8) ? "OK" : "Error"); 80 | hw.setButtonState(16, true); 81 | switches2.update(); 82 | printf("\tTest 10 - Button pressed again \t\t%s\n", switches2.getStatus(8) ? "OK" : "Error"); 83 | hw.setButtonState(16, false); 84 | switches2.update(); 85 | printf("\tTest 10 - Button pressed again \t\t%s\n", !switches2.getStatus(8) ? "OK" : "Error"); 86 | 87 | switches2.setStatus(8, true); 88 | printf("\tTest 11 - Button set externally to pressed \t\t%s\n", switches2.getStatus(8) ? "OK" : "Error"); 89 | switches2.setStatus(8, false); 90 | printf("\tTest 12 - Button set externally to released \t\t%s\n", !switches2.getStatus(8) ? "OK" : "Error");*/ 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | } 99 | -------------------------------------------------------------------------------- /Arpeggiator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Arpeggiator.cpp 3 | * 4 | * Created on: Apr 11, 2015 5 | * Author: Martin Baar 6 | */ 7 | 8 | #include "Arpeggiator.h" 9 | #include "random.h" 10 | 11 | Arpeggiator::Arpeggiator() : algorithm_(Arpeggiator::UP), windowSize_(1), count_(0), started_(false), 12 | currentIndex_(0), upDownGoingUp_(true), removeNoteAfterGettingNext_(false) 13 | { 14 | } 15 | 16 | bool Arpeggiator::addNote(unsigned char note) { 17 | if (count_ != ARPEGGIATOR_MAX_VALUES) { 18 | unsigned char valueIndex; 19 | if (!findValue(note, notes_, valueIndex)) { 20 | notes_[count_] = note; 21 | count_++; 22 | fillSorted(); 23 | return true; 24 | } 25 | } 26 | return false; 27 | } 28 | 29 | bool Arpeggiator::removeNote(unsigned char note) { 30 | 31 | //When note is just playing we shall remove it later when we want to do another step 32 | if (note == notes_[currentIndex_]) { 33 | removeNoteAfterGettingNext_ = true; 34 | return true; 35 | } else { 36 | unsigned char valueIndex; 37 | if (findValue(note, notes_, valueIndex)) { 38 | if (valueIndex < currentIndex_) { 39 | currentIndex_--; 40 | } 41 | for (unsigned char i = valueIndex; i < (count_ - 1); i++) { 42 | notes_[i] = notes_[i + 1]; 43 | } 44 | count_--; 45 | fillSorted(); 46 | return true; 47 | } 48 | } 49 | return false; 50 | } 51 | 52 | bool Arpeggiator::getNextNote(unsigned char& note) { 53 | if (count_ != 0) { 54 | unsigned char oldIndex = currentIndex_; 55 | do { 56 | currentIndex_ = getNextIndex(); 57 | } while (currentIndex_ < (count_ - windowSize_)); 58 | note = notes_[currentIndex_]; 59 | if (removeNoteAfterGettingNext_) { 60 | removeNote(notes_[oldIndex]); 61 | removeNoteAfterGettingNext_ = false; 62 | if (count_ == 0) { 63 | return false; 64 | } 65 | } 66 | return true; 67 | } 68 | return false; 69 | } 70 | 71 | bool Arpeggiator::findValue(unsigned char value, unsigned char* array, unsigned char& index) { 72 | for (unsigned char i = 0; i < count_; i++) { 73 | if (array[i] == value) { 74 | index = i; 75 | return true; 76 | } 77 | } 78 | return false; 79 | } 80 | 81 | unsigned char Arpeggiator::getNextIndex() { 82 | if (started_) { 83 | switch (algorithm_) { 84 | case Arpeggiator::UP : 85 | return (currentIndex_ + 1) % count_; 86 | case Arpeggiator::DOWN: 87 | return (currentIndex_ == 0) ? (count_ - 1) : (currentIndex_ - 1); 88 | case Arpeggiator::UP_DOWN: 89 | unsigned char newIndex; 90 | if (upDownGoingUp_) { 91 | if ((currentIndex_ + 1) == count_) { 92 | upDownGoingUp_ = false; 93 | return currentIndex_ - 1; 94 | } else { 95 | return (currentIndex_ + 1) % count_; 96 | } 97 | } else { 98 | if (currentIndex_ == 0 || (currentIndex_ == count_ - windowSize_)) { 99 | upDownGoingUp_ = true; 100 | return (currentIndex_ + 1) % count_; 101 | } else { 102 | return currentIndex_ - 1; 103 | } 104 | } 105 | if (newIndex == (count_ - 1) || newIndex == (count_ - windowSize_) || newIndex == 0) { 106 | upDownGoingUp_ = ! upDownGoingUp_; 107 | } 108 | return newIndex; 109 | case Arpeggiator::SORTED: 110 | unsigned char indexInSorted; 111 | findValue(currentIndex_, sortedNotes_, indexInSorted); 112 | return sortedNotes_[(indexInSorted + 1) % count_]; 113 | case Arpeggiator::RANDOM: 114 | return bastlRandom::range(count_- windowSize_, count_ - 1); 115 | default: 116 | return currentIndex_; 117 | } 118 | } else { 119 | 120 | //Sequence just started so based on used algorithm we have to return 121 | //correct first note to play 122 | started_ = true; 123 | 124 | //For Down initial index is last item not the first one! 125 | if (algorithm_ == Arpeggiator::DOWN) { 126 | currentIndex_ = (count_ - 1); 127 | } else if (algorithm_ == Arpeggiator::SORTED) { 128 | currentIndex_ = sortedNotes_[0]; 129 | } else { 130 | currentIndex_ = 0; 131 | upDownGoingUp_ = true; 132 | } 133 | } 134 | return currentIndex_; 135 | } 136 | 137 | void Arpeggiator::fillSorted() { 138 | for (unsigned char sourceIndex = 0; sourceIndex < count_; sourceIndex++) { 139 | unsigned char value = notes_[sourceIndex]; 140 | unsigned char targetIndex = 0; 141 | for (unsigned char checkedIndex = 0; checkedIndex < count_; checkedIndex++) { 142 | if (value > notes_[checkedIndex]) { 143 | targetIndex++; 144 | } 145 | } 146 | sortedNotes_[targetIndex] = sourceIndex; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /StepRecorder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * StepRecorder.cpp 3 | * 4 | * Created on: Aug 28, 2014 5 | * Author: bastl 6 | */ 7 | 8 | #include "StepRecorder.h" 9 | 10 | StepRecorder::StepRecorder() : player_(0), memory_(0), playerSettings_(0), stepper_(0), record_(true) { 11 | for (unsigned char instrument = 0; instrument < 6; instrument++) { 12 | recordInstrumentStatuses_[instrument] = false; 13 | lastQuantizedSteps_[instrument] = 0; 14 | } 15 | } 16 | 17 | void StepRecorder::init(Player* player, IStepMemory * memory, PlayerSettings* playerSettings, BastlStepper * stepper) { 18 | player_ = player; 19 | memory_ = memory; 20 | playerSettings_ = playerSettings; 21 | stepper_ = stepper; 22 | } 23 | 24 | unsigned char StepRecorder::getCurrentQuantizedSubstep(unsigned char instrumentIndex) { 25 | unsigned char currentStep = player_->getCurrentInstrumentStep(instrumentIndex); 26 | unsigned char currentSubStep = player_->getCurrentInstrumentSubStep(instrumentIndex); 27 | 28 | //Start of quantization evaluation 29 | unsigned char quantizationRate = playerSettings_->getRecordQuantizationSize(); 30 | 31 | int doubleSubstepValue = (currentStep * 4 + currentSubStep) * 2; 32 | doubleSubstepValue += stepper_->isCloserToNextStep() ? quantizationRate : 0; 33 | doubleSubstepValue = (doubleSubstepValue / (quantizationRate * 2)) * quantizationRate; 34 | return (unsigned char) doubleSubstepValue; 35 | } 36 | 37 | unsigned int StepRecorder::startRecordNote(unsigned char instrumentIndex) { 38 | 39 | recordInstrumentStatuses_[instrumentIndex] = true; 40 | lastQuantizedSteps_[instrumentIndex] = getCurrentQuantizedSubstep(instrumentIndex); 41 | if (playerSettings_->getDrumInstrumentEventType(instrumentIndex) == PlayerSettings::TRIGGER) { 42 | stopRecordNote(instrumentIndex); 43 | } else { 44 | player_->setNoteOffDisalbedState(instrumentIndex, true); 45 | recordSubsteps(instrumentIndex, lastQuantizedSteps_[instrumentIndex]); 46 | } 47 | player_->playNote(instrumentIndex, DrumStep::NORMAL); 48 | return lastQuantizedSteps_[instrumentIndex]; 49 | } 50 | 51 | void StepRecorder::update() { 52 | 53 | for (unsigned char instrument = 0; instrument < 6; instrument++) { 54 | if (playerSettings_->getDrumInstrumentEventType(instrument) == PlayerSettings::GATE) { 55 | if (recordInstrumentStatuses_[instrument]) { 56 | unsigned char currentQuantizedStep = getCurrentQuantizedSubstep(instrument); 57 | if (currentQuantizedStep != lastQuantizedSteps_[instrument]) { 58 | recordSubsteps(instrument, lastQuantizedSteps_[instrument]); 59 | lastQuantizedSteps_[instrument] = currentQuantizedStep; 60 | } 61 | player_->playNote(instrument, DrumStep::NORMAL, false); 62 | } 63 | } 64 | } 65 | } 66 | 67 | void StepRecorder::recordSubsteps(unsigned char instrumentIndex, unsigned char subStepStartIndex) { 68 | if (record_) { 69 | unsigned char size = playerSettings_->getDrumInstrumentEventType(instrumentIndex) == PlayerSettings::GATE ? 70 | playerSettings_->getRecordQuantizationSize() : 1; 71 | for (unsigned char subStepIndex = 0; subStepIndex < size; subStepIndex++) { 72 | unsigned char currentStep = (unsigned char)((subStepIndex + subStepStartIndex) / 4); 73 | unsigned char currentSubStep = (unsigned char)((subStepIndex + subStepStartIndex) % 4); 74 | //End of quantization evaluation 75 | DrumStep manipulatedDrumStep = memory_->getDrumStep(instrumentIndex, currentStep); 76 | if (manipulatedDrumStep.isMuted()) { 77 | manipulatedDrumStep.setMuted(false); 78 | for (unsigned char subStep = 0; subStep < 4; subStep++) { 79 | manipulatedDrumStep.setSubStep(subStep, DrumStep::OFF); 80 | } 81 | } 82 | manipulatedDrumStep.setSubStep(currentSubStep, DrumStep::NORMAL); 83 | memory_->setDrumStep(instrumentIndex, currentStep, manipulatedDrumStep); 84 | } 85 | } 86 | } 87 | 88 | void StepRecorder::stopRecordNote(unsigned char instrumentIndex) { 89 | 90 | if (recordInstrumentStatuses_[instrumentIndex]) { 91 | recordInstrumentStatuses_[instrumentIndex] = false; 92 | recordSubsteps(instrumentIndex, lastQuantizedSteps_[instrumentIndex]); 93 | player_->playNote(instrumentIndex, DrumStep::NORMAL, false); 94 | player_->setNoteOffDisalbedState(instrumentIndex, false); 95 | } 96 | } 97 | 98 | void StepRecorder::recordMIDINote(unsigned char channel, unsigned char note) { 99 | unsigned char instrumentID = 0; 100 | bool instrumentMapped = false;//playerSettings_->getDrumInstrumentIndexFromMIDIMessage(channel, note, instrumentID); 101 | if (instrumentMapped) { 102 | startRecordNote(instrumentID); 103 | stopRecordNote(instrumentID); 104 | } 105 | } 106 | 107 | -------------------------------------------------------------------------------- /Player.h: -------------------------------------------------------------------------------- 1 | #ifndef PLAYER_H 2 | #define PLAYER_H 3 | 4 | //#define DEBUG 5 | 6 | #include "IStepMemory.h" 7 | #include "RackInstrumentDefinitions.h" 8 | #include "PlayerSettings.h" 9 | #include "StepSynchronizer.h" 10 | 11 | 12 | #ifdef DEBUG 13 | 14 | #include 15 | 16 | #endif 17 | 18 | /** 19 | * @brief The Player class that plays defined pattern for soecific instruments 20 | */ 21 | class Player 22 | { 23 | public: 24 | Player(IStepMemory * memory, 25 | PlayerSettings * settings, 26 | StepSynchronizer * synchronizer, 27 | void (*instrumentEventCallback)(unsigned char instrumentID, 28 | DrumStep::DrumVelocityType velocityType, 29 | bool isOn) 30 | ); 31 | void stepFourth(); 32 | unsigned char getCurrentInstrumentStep(unsigned char instrumentID); 33 | void setCurrentInstrumentStep(unsigned char instrumentID, unsigned char step); 34 | void changeActivesForCurrentStep(unsigned char instrumentID, unsigned char numberOfActiveSteps); 35 | void changeActivesForCurrentStepInAllInstrunents(unsigned char numberOfActiveSteps); 36 | 37 | unsigned char getCurrentInstrumentSubStep(unsigned char instrumentID); 38 | void playNote(unsigned char instrumentID, DrumStep::DrumVelocityType velocityType, bool sendNoteOffBefore = true); 39 | void resetAllInstruments(); 40 | void startLoop(unsigned char step); 41 | void stopLoop(); 42 | bool isPlaying(); 43 | void update(unsigned int elapsedTimeUnits); 44 | void setNoteOffDisalbedState(unsigned char instrument, bool disabled); 45 | 46 | private: 47 | IStepMemory * memory_; 48 | PlayerSettings * settings_; 49 | StepSynchronizer * synchronizer_; 50 | unsigned char currentSteps_[INSTRUMENTS]; 51 | unsigned char playingInstruments[ALL_INSTRUMENTS_IN_BYTES]; 52 | bool isStopped_; 53 | bool inLoop_; 54 | unsigned char loopedStep_; 55 | void (*instrumentEventCallback_)(unsigned char instrumentID, DrumStep::DrumVelocityType velocityType, bool isOn); 56 | unsigned int lastElapsedTimeUnits_; 57 | unsigned int lastDummyPlayInstrumentTimeUnits_; 58 | unsigned char noteOffDisabledInstruments_; 59 | void stepDrumInstruments(); 60 | bool isInstrumentPlaying(unsigned char instrumentID); 61 | void setInstrumentPlaying(unsigned char instrumentID, bool isPlaying); 62 | void sendNoteOffIfPlaying(unsigned char instrumentID); 63 | 64 | }; 65 | 66 | inline void Player::startLoop(unsigned char step) { 67 | inLoop_ = true; 68 | loopedStep_ = step; 69 | } 70 | 71 | inline void Player::stopLoop() { 72 | inLoop_ = false; 73 | } 74 | 75 | inline unsigned char Player::getCurrentInstrumentStep(unsigned char instrumentID) { 76 | return currentSteps_[instrumentID] / 4; 77 | } 78 | 79 | inline void Player::setCurrentInstrumentStep(unsigned char instrumentID, unsigned char step) { 80 | currentSteps_[instrumentID] = step * 4 + currentSteps_[instrumentID] % 4; 81 | } 82 | 83 | inline unsigned char Player::getCurrentInstrumentSubStep(unsigned char instrumentID) { 84 | return currentSteps_[instrumentID] % 4; 85 | } 86 | 87 | inline bool Player::isInstrumentPlaying(unsigned char instrumentID) 88 | { 89 | #ifdef DEBUG 90 | printf("Instrument %i, DataIndex %i,Data %i\n", instrumentID, instrumentID / 8, playingInstruments[instrumentID / 8]); 91 | printf("dataAfterSwitch : %i \n", (playingInstruments[instrumentID / 8] & (1 << (instrumentID % 8)))); 92 | #endif 93 | return (((playingInstruments[instrumentID / 8] & (1 << (instrumentID % 8))) >> (instrumentID % 8))) == 1; 94 | } 95 | 96 | inline void Player::setInstrumentPlaying(unsigned char instrumentID, bool isPlaying) 97 | { 98 | if (isPlaying) { 99 | #ifdef DEBUG 100 | printf("Set playing true Instrument %i, DataIndex %i,Data %i\n", instrumentID, instrumentID / 8, playingInstruments[instrumentID / 8]); 101 | #endif 102 | playingInstruments[instrumentID / 8] = playingInstruments[instrumentID / 8] | (1 << (instrumentID % 8)); 103 | } else { 104 | #ifdef DEBUG 105 | printf("Set playing false Instrument %i, DataIndex %i,Data %i\n", instrumentID, instrumentID / 8, playingInstruments[instrumentID / 8]); 106 | #endif 107 | playingInstruments[instrumentID / 8] = playingInstruments[instrumentID / 8] & ~(1 << (instrumentID % 8)); 108 | } 109 | } 110 | 111 | inline bool Player::isPlaying() { 112 | return !isStopped_; 113 | } 114 | 115 | inline void Player::setNoteOffDisalbedState(unsigned char instrument, bool disabled) { 116 | setBit(noteOffDisabledInstruments_, instrument, disabled); 117 | } 118 | #endif // PLAYER_H 119 | -------------------------------------------------------------------------------- /Player.cpp: -------------------------------------------------------------------------------- 1 | #include "Player.h" 2 | #include "IStepMemory.h" 3 | 4 | #define SUBSTEPS_PER_STEP 4 5 | 6 | Player::Player(IStepMemory * memory, 7 | PlayerSettings * settings, 8 | StepSynchronizer * synchronizer, 9 | void (*instrumentEventCallback)(unsigned char instrumentID, DrumStep::DrumVelocityType velocityType, bool isOn) 10 | ) : memory_(memory), 11 | settings_(settings), 12 | synchronizer_(synchronizer), 13 | isStopped_(true), 14 | inLoop_(false), 15 | loopedStep_(6), 16 | instrumentEventCallback_(instrumentEventCallback), 17 | noteOffDisabledInstruments_(0) 18 | { 19 | for (unsigned char i = 0; i < INSTRUMENTS; i++) { 20 | currentSteps_[i] = 0; 21 | } 22 | for (unsigned char i = 0 ; i < ALL_INSTRUMENTS_IN_BYTES; i++) { 23 | playingInstruments[i] = 0; 24 | } 25 | } 26 | 27 | void Player::stepFourth() 28 | { 29 | stepDrumInstruments(); 30 | } 31 | 32 | void Player::update(unsigned int elapsedTimeUnits) { 33 | if (isStopped_ && (elapsedTimeUnits - lastDummyPlayInstrumentTimeUnits_) > 20) { 34 | resetAllInstruments(); 35 | } 36 | lastElapsedTimeUnits_ = elapsedTimeUnits; 37 | } 38 | 39 | void Player::playNote(unsigned char instrumentID, DrumStep::DrumVelocityType velocityType, bool sendNoteOffBefore) { 40 | if (sendNoteOffBefore) 41 | sendNoteOffIfPlaying(instrumentID); 42 | if (isStopped_) { 43 | instrumentEventCallback_(instrumentID, velocityType, true); 44 | setInstrumentPlaying(instrumentID, true); 45 | lastDummyPlayInstrumentTimeUnits_ = lastElapsedTimeUnits_; 46 | } else { 47 | if (instrumentEventCallback_) { 48 | instrumentEventCallback_(instrumentID, velocityType, true); 49 | } 50 | setInstrumentPlaying(instrumentID, true); 51 | } 52 | } 53 | 54 | void Player::sendNoteOffIfPlaying(unsigned char instrumentID) { 55 | if (isInstrumentPlaying(instrumentID) && !getBit(noteOffDisabledInstruments_, instrumentID)) { 56 | if (instrumentEventCallback_) { 57 | instrumentEventCallback_(instrumentID, DrumStep::OFF , false); 58 | } 59 | setInstrumentPlaying(instrumentID, false); 60 | } 61 | } 62 | 63 | void Player::stepDrumInstruments() 64 | { 65 | for (unsigned char i = 0; i < 6; i++) { 66 | DrumStep nextStep; 67 | unsigned char nextSubStepIndex = (currentSteps_[i] + 1) % 256; 68 | if (isStopped_ ) { 69 | nextSubStepIndex = currentSteps_[i]; 70 | } 71 | bool nextStepExists = true; 72 | // when in the substep sequence dont ask for the next step otherwise ask for newxt available 73 | if (nextSubStepIndex % 4 != 0) { 74 | unsigned char nextStepIndex = nextSubStepIndex / 4; 75 | //printf("calling currentStep on for %i index is %i \n", i, nextStepIndex); 76 | nextStep = memory_->getDrumStep(i, nextStepIndex); 77 | } else { 78 | if (inLoop_) { 79 | nextStep = memory_->getDrumStep(i, loopedStep_); 80 | nextSubStepIndex = 4 * loopedStep_; 81 | } else { 82 | unsigned char currentStepIndex = nextSubStepIndex / 4; 83 | //printf("calling nextStep on for %i index is %i \n", i, currentStepIndex); 84 | nextStepExists = memory_->getNextActiveDrumStep(i, currentStepIndex, nextStep); 85 | //if (nextStepExists) printf("NextStepExists index %i\n", currentStepIndex); 86 | nextSubStepIndex = 4 * currentStepIndex; 87 | } 88 | } 89 | bool nextStepIsOn = nextStepExists && !nextStep.isMuted() && (nextStep.getSubStep(nextSubStepIndex % 4) != DrumStep::OFF); 90 | 91 | // In case this next step is on we do not have to send offs since we have hw 92 | // trigger buffer and it will take care of things 93 | if (nextStepIsOn) { 94 | playNote(i, DrumStep::NORMAL, false); 95 | } else { 96 | sendNoteOffIfPlaying(i); 97 | } 98 | if (nextStepExists) { 99 | currentSteps_[i] = nextSubStepIndex; 100 | } 101 | 102 | } 103 | isStopped_ = false; 104 | } 105 | 106 | void Player::changeActivesForCurrentStep(unsigned char instrumentID, unsigned char numberOfActiveSteps) { 107 | setCurrentInstrumentStep(instrumentID, (synchronizer_->getCurrentStepNumber() / 4) % numberOfActiveSteps); 108 | } 109 | 110 | void Player::changeActivesForCurrentStepInAllInstrunents(unsigned char numberOfActiveSteps) { 111 | for (unsigned char instrument = 0; instrument < 6; instrument++) { 112 | changeActivesForCurrentStep(instrument, numberOfActiveSteps); 113 | } 114 | } 115 | 116 | void Player::resetAllInstruments() { 117 | for (unsigned char i = 0; i < 6; i++) { 118 | sendNoteOffIfPlaying(i); 119 | currentSteps_[i] = 0; 120 | } 121 | isStopped_ = true; 122 | } 123 | -------------------------------------------------------------------------------- /modules/test/tst.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * tst.cpp 3 | * 4 | * Created on: Jul 16, 2014 5 | * Author: Martin Baar 6 | */ 7 | 8 | #include "SteppingHWLayerMock.h" 9 | #include "../Stepper.h" 10 | #include "../MIDIStepper.h" 11 | #include 12 | 13 | unsigned char numberOfSteps = 0; 14 | 15 | void doStep() { 16 | numberOfSteps++; 17 | } 18 | 19 | int main( int argc, const char* argv[] ) { 20 | SteppingHWLayerMock hw; 21 | hw.setBastlCyclesPerSecond(128); 22 | hw.setElapsedBastlCycles(0); 23 | printf("Checking Stepper\n"); 24 | Stepper stepper(&hw); 25 | stepper.setBPM(60); 26 | stepper.setStepCallback(&doStep); 27 | stepper.update(); 28 | for (int i = 0; i < 8; i++) { 29 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 30 | stepper.update(); 31 | } 32 | printf("Checking Stepper after 8 cycles: %s\n", numberOfSteps == 0 ? "OK": "ERROR"); 33 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 34 | stepper.update(); 35 | printf("Checking Stepper after another 1 cycle: %s\n", numberOfSteps == 1 ? "OK": "ERROR"); 36 | for (int i = 0; i < 7; i++) { 37 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 38 | stepper.update(); 39 | } 40 | printf("Checking Stepper after another 7 cycles: %s\n", numberOfSteps == 1 ? "OK": "ERROR"); 41 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 42 | stepper.update(); 43 | printf("Checking Stepper after another 1 cycle: %s\n", numberOfSteps == 2 ? "OK": "ERROR"); 44 | 45 | printf("Testing changed BPM\n"); 46 | 47 | stepper.setBPM(120); 48 | 49 | for (int i = 0; i < 3; i++) { 50 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 51 | stepper.update(); 52 | } 53 | printf("Checking Stepper after another 15 cycles: %s\n", numberOfSteps == 2 ? "OK": "ERROR"); 54 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 55 | stepper.update(); 56 | printf("Checking Stepper after another 1 cycle: %s\n", numberOfSteps == 3 ? "OK": "ERROR"); 57 | 58 | printf("Testing overflow\n"); 59 | stepper.setBPM(60); 60 | hw.setElapsedBastlCycles((unsigned int)(-3)); 61 | stepper.sync(); 62 | numberOfSteps = 0; 63 | printf("Testing overflow init done.\n"); 64 | for (int i = 0; i < 8; i++) { 65 | //std::cout << "Elapsed cycles " << hw.getElapsedBastlCycles() << std::endl; 66 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 67 | stepper.update(); 68 | } 69 | printf("Checking Stepper after 8 cycles: %s\n", numberOfSteps == 0 ? "OK": "ERROR"); 70 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 71 | stepper.update(); 72 | printf("Checking Stepper after another 1 cycle: %s\n", numberOfSteps == 1 ? "OK": "ERROR"); 73 | 74 | hw.setElapsedBastlCycles(0); 75 | numberOfSteps = 0; 76 | MIDIStepper midiStepper(&hw); 77 | midiStepper.setStepCallback(&doStep); 78 | midiStepper.stepMIDI(); 79 | printf("Checking Stepper after another 1 MIDI step: %s\n", numberOfSteps == 1 ? "OK": "ERROR"); 80 | for (int i = 0; i < 16; i++) { 81 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 82 | midiStepper.update(); 83 | } 84 | printf("Checking Stepper after another 1 MIDI step and 16 Bastl cycles: %s\n", numberOfSteps == 1 ? "OK": "ERROR"); 85 | midiStepper.stepMIDI(); 86 | printf("Checking Stepper after another 2 MIDI step and 16 Bastl cycles: %s\n", numberOfSteps == 2 ? "OK": "ERROR"); 87 | for (int i = 0; i < 8; i++) { 88 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 89 | midiStepper.update(); 90 | } 91 | printf("Checking Stepper after another 2 MIDI step and 24 Bastl cycles: %s\n", numberOfSteps == 2 ? "OK": "ERROR"); 92 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 93 | midiStepper.update(); 94 | printf("Checking Stepper after another 2 MIDI step and 25 Bastl cycles: %s\n", numberOfSteps == 3 ? "OK": "ERROR"); 95 | for (int i = 0; i < 7; i++) { 96 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 97 | midiStepper.update(); 98 | } 99 | printf("Checking Stepper after another 2 MIDI step and 32 Bastl cycles: %s\n", numberOfSteps == 3 ? "OK": "ERROR"); 100 | midiStepper.stepMIDI(); 101 | printf("Checking Stepper after another 3 MIDI step and 32 Bastl cycles: %s\n", numberOfSteps == 4 ? "OK": "ERROR"); 102 | 103 | 104 | for (int i = 0; i < 9; i++) { 105 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 106 | midiStepper.update(); 107 | } 108 | printf("Checking Stepper after another 3 MIDI step and 41 Bastl cycles: %s\n", numberOfSteps == 5 ? "OK": "ERROR"); 109 | for (int i = 0; i < 23; i++) { 110 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 111 | midiStepper.update(); 112 | } 113 | printf("Checking Stepper after another 3 MIDI step and 64 Bastl cycles: %s\n", numberOfSteps == 5 ? "OK": "ERROR"); 114 | midiStepper.stepMIDI(); 115 | printf("Checking Stepper after another 4 MIDI step and 64 Bastl cycles: %s\n", numberOfSteps == 6 ? "OK": "ERROR"); 116 | for (int i = 0; i < 17; i++) { 117 | hw.setElapsedBastlCycles(hw.getElapsedBastlCycles() + 1); 118 | midiStepper.update(); 119 | } 120 | printf("Checking Stepper after another 4 MIDI step and 97 Bastl cycles: %s\n", numberOfSteps == 7 ? "OK": "ERROR"); 121 | } 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /trinityRack_HW.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | trinityHWR.cpp library 4 | this library is to be used with standuino fraAngelico hardware 5 | MOZZI library compatible 6 | documentation of the library you find here: 7 | trinityHWR library 8 | 9 | Created by Vaclav Pelousek 2013 www.pelousek.eu 10 | for Standuino wwww.standuino.eu 11 | 12 | */ 13 | 14 | #ifndef trinityHWR_h 15 | #define trinityHWR_h 16 | 17 | #include "Arduino.h" 18 | #include 19 | //#include 20 | 21 | 22 | #define DEFAULT 0 23 | #define UNFREEZE_EXTERNALY 1 24 | 25 | #define FALSE 0 26 | #define TRUE 1 27 | 28 | #define NUMBER_OF_KNOBS 3 29 | #define NUMBER_OF_BIG_BUTTONS 3 30 | #define NUMBER_OF_BUTTONS 7 31 | #define NUMBER_OF_LEDS 6 32 | 33 | 34 | // pin definitions // 35 | 36 | #define KNOB_1_PIN A1 37 | #define KNOB_2_PIN A4 38 | #define KNOB_3_PIN A2 //A3 39 | 40 | //#define REVERSED_BOARD 1 41 | 42 | 43 | 44 | #define BIG_BUTTON_1_PIN 8 45 | #define BIG_BUTTON_2_PIN 13 46 | #define BIG_BUTTON_3_PIN 12 47 | 48 | 49 | #define SMALL_BUTTON_1_PIN 17 50 | #define SMALL_BUTTON_2_PIN 11 //18 51 | 52 | #define EXTRA_BUTTON_1_PIN 19 53 | #define EXTRA_BUTTON_2_PIN 14 54 | 55 | 56 | #define LED_1_PIN 2 57 | #define LED_2_PIN 6 58 | #define LED_3_PIN 7 59 | 60 | 61 | //TAYDA RGB 62 | #define LED_R_PIN 5 63 | #define LED_G_PIN 3 64 | #define LED_B_PIN 4 65 | 66 | /* 67 | //GME RGB 68 | #define LED_R_PIN 4 69 | #define LED_G_PIN 5 70 | #define LED_B_PIN 3 71 | // 72 | */ 73 | 74 | #define ZERO 0 75 | 76 | 77 | 78 | #define FACTORY_CLEAR_PIN 2 79 | #define FACTORY_CLEAR_SIGNAL_PIN 13 80 | 81 | // logic definitions // 82 | 83 | 84 | #define ACTIVITY_LIMIT 25 85 | #define KNOB_FREEZE_DISTANCE 32 86 | 87 | #define KNOB_1 0 88 | #define KNOB_2 1 89 | #define KNOB_3 2 90 | 91 | #define KNOB_TOP 0 92 | #define KNOB_LEFT 1 93 | #define KNOB_RIGHT 2 94 | 95 | #define TOP_KNOB 0 96 | #define LEFT_KNOB 1 97 | #define RIGHT_KNOB 2 98 | 99 | #define BIG_BUTTON_1 0 100 | #define BIG_BUTTON_2 1 101 | #define BIG_BUTTON_3 2 102 | 103 | #define BIG_BUTT_1 0 104 | #define BIG_BUTT_2 1 105 | #define BIG_BUTT_3 2 106 | 107 | #define SMALL_BUTTON_1 3 108 | #define SMALL_BUTTON_2 4 109 | 110 | #define EXTRA_BUTTON_1 5 111 | #define EXTRA_BUTTON_2 6 112 | 113 | #define SMALL_BUTT_1 3 114 | #define SMALL_BUTT_2 4 115 | 116 | #define EXTRA_BUTT_1 5 117 | #define EXTRA_BUTT_2 6 118 | 119 | #define LED_1 0 120 | #define LED_2 1 121 | #define LED_3 2 122 | #define LED_R 3 123 | #define LED_G 4 124 | #define LED_B 5 125 | 126 | 127 | #define NUMBER_OF_COLORS 8 128 | 129 | #define BLACK 0 130 | #define RED 1 131 | #define GREEN 2 132 | #define BLUE 3 133 | #define YELLOW 4 134 | #define MAGENTA 5 135 | #define CIAN 6 136 | #define WHITE 7 137 | 138 | #define BLACK_BITS 0 139 | #define RED_BITS 1 140 | #define GREEN_BITS 2 141 | #define BLUE_BITS 4 142 | #define YELLOW_BITS 3 143 | #define MAGENTA_BITS 5 144 | #define CIAN_BITS 6 145 | #define WHITE_BITS 7 146 | 147 | 148 | 149 | 150 | // extern int led; i can acces from the main 151 | 152 | 153 | class trinityHWR 154 | { 155 | public: 156 | 157 | trinityHWR(); // constructor 158 | void initialize(unsigned char _HW_VERSION); 159 | void initializeMozzi(unsigned char _HW_VERSION); 160 | void update(); 161 | void mozziUpdate(); 162 | 163 | void setLed(unsigned char _LED, boolean _STATE); 164 | void setColor(unsigned char _COLOR); 165 | 166 | boolean buttonState(unsigned char _BUTTON); // LFO // LEARD // EDIT 167 | boolean justPressed(unsigned char _BUTTON); 168 | boolean justReleased(unsigned char _BUTTON); 169 | 170 | boolean knobFreezed(unsigned char _KNOB); 171 | boolean knobMoved(unsigned char _KNOB); 172 | 173 | void freezeAllKnobs(); 174 | void unfreezeAllKnobs(); 175 | void freezeKnob(unsigned char _KNOB); 176 | void unfreezeKnob(unsigned char _KNOB); 177 | int knobValue(unsigned char _KNOB); 178 | int lastKnobValue(unsigned char _KNOB); 179 | 180 | void setFreezeType(unsigned char _TYPE); 181 | 182 | void setKnobTolerance(unsigned char _tolerance); 183 | 184 | 185 | void flipSwitch(unsigned char _SWITCH); 186 | void setSwitch(unsigned char _SWITCH, boolean _STATE); 187 | boolean switchState(unsigned char _SWITCH); 188 | void resetSwitches(); 189 | 190 | 191 | unsigned char soundFromSwitches(); 192 | unsigned char soundFromButtons(); 193 | 194 | boolean factoryClear(); 195 | void factoryCleared(); 196 | void setIndependentRGBState(boolean _STATE); 197 | 198 | 199 | private: 200 | boolean independentRGB; 201 | unsigned char KNOB_TOLERANCE; 202 | unsigned char activity; 203 | int buttonStateHash; 204 | int lastButtonStateHash; 205 | int switchStateHash; 206 | int justPressedHash; // change 207 | int justReleasedHash; 208 | unsigned char ledStateHash; 209 | unsigned char knobFreezedHash; 210 | unsigned char knobChangedHash; 211 | int knobValues[NUMBER_OF_KNOBS]; 212 | int lastKnobValues[NUMBER_OF_KNOBS]; 213 | boolean mozziDigitalRead(unsigned char _pin); 214 | void updateMozziKnobs(); 215 | void updateKnobs(); 216 | void updateButtons(); 217 | void updateMozziButtons(); 218 | void writeToLeds(); 219 | 220 | boolean mozzi; 221 | boolean unfreezeExternaly; 222 | 223 | 224 | }; 225 | #endif /* TRINITYRACK_HW_H_ */ 226 | -------------------------------------------------------------------------------- /lfoExtended.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * lfoExtended.cpp 3 | * 4 | * Created on: 30.01.2015 5 | * Author: user 6 | */ 7 | 8 | #include "lfoExtended.h" 9 | #include "random.h" 10 | 11 | 12 | 13 | //#define VERBOSE 14 | 15 | void lfoExtended::init(uint16_t bastlCycleFrequency) { 16 | currentWaveform = SAW; 17 | numbPhaseStepsToSkip = 0; 18 | threshold = 255; 19 | thresholdType = FOLDING; 20 | currentStep = 0; 21 | lastUnskippedPhase = 0; 22 | currentSlope = 0; 23 | xorBits = 0; 24 | flopBits=0; 25 | currentPhase = 0; 26 | lastTimeStamp = 0; 27 | 28 | this->bastlCycleFrequency = bastlCycleFrequency; 29 | 30 | } 31 | 32 | void lfoExtended::setBastlCyclesPerPeriod(uint16_t bastlCyclesPerPeriod) { 33 | if (bastlCyclesPerPeriod==0) { 34 | phaseIncrement = 0; 35 | return; 36 | } 37 | 38 | phaseIncrement = ((uint32_t)65536 + (bastlCyclesPerPeriod>>1))/bastlCyclesPerPeriod; 39 | maxAbsoluteSlope = ((uint16_t)phaseIncrement+100)>>6; 40 | #ifdef VERBOSE 41 | printf("Cycles per Period %u = phaseincrement of %u\n",bastlCyclesPerPeriod,phaseIncrement); 42 | printf("Random max Steps betweene slope change: %u \n\n",maxStepsBetweenSlopeChange); 43 | #endif 44 | } 45 | 46 | void lfoExtended::setWaveform(LFOBasicWaveform waveform) { 47 | currentWaveform = waveform; 48 | } 49 | void lfoExtended::setXOR(uint8_t xorBits) { 50 | this->xorBits = xorBits; 51 | } 52 | 53 | void lfoExtended::setFlop(uint8_t flopBits) { 54 | this->flopBits = flopBits; 55 | } 56 | 57 | void lfoExtended::setResolution(uint8_t stepsPerPeriod) { 58 | if (stepsPerPeriod == 0) stepsPerPeriod = 1; // preventing division by zero 59 | 60 | this->numbPhaseStepsToSkip = ((uint32_t)65536/(stepsPerPeriod)-2); 61 | #ifdef VERBOSE 62 | printf("\nPhase steps to skip %u\n",numbPhaseStepsToSkip); 63 | #endif 64 | } 65 | 66 | void lfoExtended::setThreshold(uint8_t thres,LFOThresholdType type) { 67 | threshold = thres; 68 | thresholdType = type; 69 | } 70 | 71 | void lfoExtended::setToStep(uint8_t step, uint16_t time) { 72 | currentPhase = step << 8; 73 | //lastTimeStamp = time; 74 | } 75 | 76 | 77 | uint8_t lfoExtended::getValue(uint16_t timestamp) { 78 | 79 | while(lastTimeStamp!=timestamp) { 80 | step(); 81 | lastTimeStamp++; 82 | } 83 | 84 | return getValue(); 85 | } 86 | uint8_t lfoExtended::getPhase(){ 87 | return currentPhase >> 8; 88 | } 89 | uint8_t lfoExtended::getValue() { 90 | 91 | #ifdef VERBOSE 92 | printf("Getting output for %u\n",currentPhase); 93 | #endif 94 | 95 | // check if step will be skipped due to resolution 96 | uint16_t phaseStepsSinceLast = currentPhase-lastUnskippedPhase; 97 | 98 | #ifdef VERBOSE 99 | printf("Phase Steps since last Call: %u\n",phaseStepsSinceLast); 100 | #endif 101 | 102 | // Break down current Phase to current Step // 103 | currentStep = currentPhase >> 8; 104 | 105 | 106 | // check if flopping is taking affect 107 | if ((currentStep & flopBits)) { 108 | return 0; 109 | } 110 | 111 | // check if resolution is taking affect 112 | if (phaseStepsSinceLast < numbPhaseStepsToSkip) { 113 | return currentOutput; 114 | } else { 115 | lastUnskippedPhase += numbPhaseStepsToSkip; 116 | } 117 | 118 | 119 | // check how many whole steps have passed to decide if new random slope must be chosen 120 | uint8_t stepsSinceLast = currentStep - lastStep; 121 | if (stepsSinceLast) lastStep = currentStep; 122 | 123 | 124 | 125 | 126 | if (currentWaveform == RANDOM) { 127 | 128 | // count down the steps that this slope is used 129 | stepsUntilNextSlopePick -= stepsSinceLast; 130 | 131 | // get new slope and its duration if it's time for it 132 | if (stepsUntilNextSlopePick <= 0) { 133 | currentSlope = bastlRandom::range(0,(2*maxAbsoluteSlope))-maxAbsoluteSlope; 134 | stepsUntilNextSlopePick = bastlRandom::range(20/2,40); 135 | #ifdef VERBOSE 136 | printf("\nPick: %i for %i\n",currentSlope,stepsUntilNextSlopePick); 137 | #endif 138 | } 139 | 140 | 141 | // check direction of slope if folding 142 | if (thresholdType == FOLDING) { 143 | int16_t tmpCurrentValue = currentOutput+currentSlope;//*stepsSinceLast; 144 | if ((tmpCurrentValue > threshold) || (tmpCurrentValue <0)) { 145 | currentSlope = -currentSlope; 146 | } 147 | } 148 | 149 | // add new slope to current output value 150 | currentOutput += currentSlope;//*stepsSinceLast; 151 | 152 | 153 | } else { 154 | 155 | // render Basic Waveform 156 | switch(currentWaveform) { 157 | 158 | case SAW: { 159 | currentOutput = currentStep; 160 | break; 161 | } 162 | 163 | case TRIANGLE: { 164 | if (currentStep < 128) currentOutput = currentStep*2; 165 | else currentOutput = 255-((currentStep*2)-255); 166 | break; 167 | } 168 | 169 | default: break; 170 | } 171 | 172 | } 173 | 174 | // Apply Overflowing 175 | if (currentOutput > threshold) { 176 | if (thresholdType == OVERFLOW) { 177 | currentOutput = currentOutput % threshold; 178 | } else { 179 | // FOLDING 180 | uint8_t sectorNumber = currentOutput/threshold; 181 | if (sectorNumber & 1) currentOutput = threshold - (currentOutput % threshold); 182 | else currentOutput = currentOutput % threshold; 183 | } 184 | } 185 | 186 | 187 | 188 | // apply XOR Bits 189 | currentOutput ^= xorBits; 190 | 191 | 192 | 193 | return currentOutput; 194 | } 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /mapping.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mapping.h 3 | * 4 | * Created on: 10.11.2014 5 | * Author: user 6 | */ 7 | 8 | #ifndef MAPPING_H_ 9 | #define MAPPING_H_ 10 | 11 | #include "basic.h" 12 | 13 | #ifndef TESTING 14 | #include 15 | 16 | 17 | const uint16_t expByteToWord_Table[256] PROGMEM = 18 | { 19 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 20 | 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 21 | 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15, 22 | 15, 16, 17, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 23 | 31, 32, 33, 35, 36, 38, 40, 41, 43, 45, 47, 49, 52, 54, 56, 59, 24 | 61, 64, 67, 70, 73, 76, 79, 83, 87, 91, 95, 99, 103, 108, 112, 25 | 117, 123, 128, 134, 140, 146, 152, 159, 166, 173, 181, 189, 197, 26 | 206, 215, 225, 235, 245, 256, 267, 279, 292, 304, 318, 332, 347, 27 | 362, 378, 395, 412, 431, 450, 470, 490, 512, 535, 558, 583, 609, 28 | 636, 664, 693, 724, 756, 790, 825, 861, 899, 939, 981, 1024, 1069, 29 | 1117, 1166, 1218, 1272, 1328, 1387, 1448, 1512, 1579, 1649, 1722, 30 | 1798, 1878, 1961, 2048, 2139, 2233, 2332, 2435, 2543, 2656, 2773, 31 | 2896, 3025, 3158, 3298, 3444, 3597, 3756, 3922, 4096, 4277, 4467, 32 | 4664, 4871, 5087, 5312, 5547, 5793, 6049, 6317, 6596, 6889, 7194, 33 | 7512, 7845, 8192, 8555, 8933, 9329, 9742, 10173, 10624, 11094, 34 | 11585, 12098, 12634, 13193, 13777, 14387, 15024, 15689, 16384, 35 | 17109, 17867, 18658, 19484, 20346, 21247, 22188, 23170, 24196, 36 | 25267, 26386, 27554, 28774, 30048, 31378, 32768, 34218, 35733, 37 | 37315, 38967, 40693, 42494, 44376, 46340, 48392, 50534, 52772, 38 | 55108, 57548, 60096, 62757, 65535 39 | }; 40 | 41 | const uint16_t exp8BitTo12BitTable[256] PROGMEM = 42 | { 43 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1, 44 | 2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,4,4,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7, 45 | 7,8,8,8,9,9,9,10,10,10,11,11,12,12,12,13,13,14,14,15,15,16,17,17, 46 | 18,18,19,20,20,21,22,23,23,24,25,26,27,28,29,30,31,32,33,34,35,37, 47 | 38,39,40,42,43,45,46,48,49,51,53,55,57,58,60,63,65,67,69,71,74,76, 48 | 79,81,84,87,90,93,96,99,103,106,110,113,117,121,125,129,134,138,143, 49 | 147,152,157,163,168,174,180,185,192,198,205,211,218,226,233,241,249, 50 | 257,266,275,284,293,303,313,323,334,345,357,368,381,393,406,420,434, 51 | 448,463,478,494,511,527,545,563,582,601,621,641,662,684,707,730,755, 52 | 780,805,832,860,888,917,948,979,1011,1045,1079,1115,1152,1190,1230, 53 | 1270,1312,1356,1400,1447,1494,1544,1595,1648,1702,1758,1816,1877,1939, 54 | 2003,2069,2137,2208,2281,2356,2434,2514,2598,2683,2772,2864,2958,3056, 55 | 3157,3261,3369,3480,3595,3714,3837,3964,4095 56 | }; 57 | 58 | const uint8_t exp8BitTo8BitTableRAM[256] = 59 | { 60 | 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2, 61 | 2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4, 62 | 4,4,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,7,7,7,7,7,7,8,8,8,8,8,9,9,9,9,9, 63 | 10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,14,14,14,14,15,15,16,16,16, 64 | 17,17,17,18,18,19,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,27,27, 65 | 28,28,29,30,30,31,32,32,33,34,35,35,36,37,38,39,40,40,41,42,43,44,45,46, 66 | 47,48,49,50,52,53,54,55,56,58,59,60,61,63,64,66,67,69,70,72,73,75,77,78, 67 | 80,82,84,85,87,89,91,93,95,97,100,102,104,106,109,111,114,116,119,121,124, 68 | 127,130,132,135,138,141,145,148,151,154,158,161,165,169,172,176,180,184,188, 69 | 192,196,201,205,210,214,219,224,229,234,239,245,250,255 70 | }; 71 | 72 | inline uint8_t mapProgmemU8U8(uint8_t input, const uint8_t table[]) { 73 | return pgm_read_byte_near(table + input); 74 | } 75 | 76 | inline uint16_t mapProgmemU8U16(uint8_t input, const uint16_t table[]) { 77 | return pgm_read_word_near(table + input); 78 | } 79 | 80 | inline uint8_t mapRAMU8U8(uint8_t input, const uint8_t table[]) { 81 | return table[input]; 82 | } 83 | 84 | #endif 85 | 86 | // General mapping from arduino 87 | 88 | int32_t map(int32_t x, int32_t in_min, int32_t in_max, int32_t out_min, int32_t out_max) { 89 | return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; 90 | } 91 | 92 | /********** Do we actually neeed this stuff? ************/ 93 | 94 | 95 | // maps the range of a input byte to a given range of an unsigned int 96 | // this is fast but NOT fully reaching the end value! 97 | inline uint16_t mapLinearRuntimeFastU8U16(uint8_t input, uint16_t start, uint16_t end) { 98 | return (((int32_t)input*(end-start))>>8)+start; 99 | } 100 | 101 | // maps the range of a input byte to a given range of an unsigned int 102 | // this is slower but reaching the end value 103 | inline uint16_t mapLinearRuntimePreciseU8U16(uint8_t input, uint16_t start, uint16_t end) { 104 | return (((int32_t)input*(end-start))/255)+start; 105 | } 106 | 107 | // maps the range of a input byte to a given range of an signed int 108 | // this is fast but NOT fully reaching the end value! 109 | inline int16_t mapLinearRuntimeFastU8S16(uint8_t input, int16_t start, int16_t end) { 110 | return (((int32_t)input*(end-start))>>8)+start; 111 | } 112 | 113 | // maps the range of a input byte to a given range of an signed int 114 | // this is slower but reaching the end value 115 | inline int16_t mapLinearRuntimePreciseU8S16(uint8_t input, int16_t start, int16_t end) { 116 | return (((int32_t)input*(end-start))/255)+start; 117 | } 118 | 119 | 120 | 121 | #endif /* MAPPING_H_ */ 122 | -------------------------------------------------------------------------------- /FlashStepMemory.cpp: -------------------------------------------------------------------------------- 1 | #include "FlashStepMemory.h" 2 | #include "RackInstrumentDefinitions.h" 3 | 4 | #define INSTRUMENT_DATA_OFFSET 5 | 6 | //#define DEBUG 7 | #ifdef DEBUG 8 | 9 | #include 10 | 11 | #endif 12 | 13 | FlashStepMemory::FlashStepMemory(IHWLayer *hwLayer) : hwLayer_(hwLayer) 14 | { 15 | } 16 | 17 | DrumStep FlashStepMemory::getDrumStep(unsigned char instrumentID, unsigned char pattern, unsigned char step) 18 | { 19 | unsigned char byteIndex = step / 8; 20 | unsigned char bitIndex = step % 8; 21 | 22 | long instrumentOffset = (STEPS_PER_PATTERN * INSTRUMENTS * pattern) /* patterbs offset */ + 23 | (STEPS_PER_PATTERN * instrumentID) /* instruments offset */ ; 24 | 25 | unsigned char actives = hwLayer_->readSRAM(instrumentOffset + byteIndex); 26 | unsigned char mutes = hwLayer_->readSRAM(instrumentOffset + byteIndex + 8); 27 | unsigned char data = hwLayer_->readSRAM(instrumentOffset + 16 + step); 28 | 29 | bool mute = ((mutes & (1 << bitIndex)) >> bitIndex) == 1; 30 | bool active = ((actives & (1 << bitIndex)) >> bitIndex) == 1; 31 | 32 | DrumStep::DrumVelocityType subSteps[4] = {DrumStep::OFF, DrumStep::OFF, DrumStep::OFF, DrumStep::OFF}; 33 | for (unsigned char i = 0; i < 4; i++) { 34 | subSteps[i] = (DrumStep::DrumVelocityType)(((3 << (i * 2)) & data) >> (i * 2)); 35 | } 36 | return DrumStep(mute, subSteps); 37 | } 38 | 39 | 40 | 41 | bool FlashStepMemory::getNextActiveDrumStep(unsigned char instrumentID, unsigned char pattern, unsigned char &step, DrumStep &drumStep) 42 | { 43 | unsigned char byteIndex = step / 8; 44 | unsigned char originalByteIndex = byteIndex; 45 | unsigned char bitIndex = step % 8; 46 | 47 | long instrumentOffset = (STEPS_PER_PATTERN * INSTRUMENTS * pattern) /* patterbs offset */ + 48 | (STEPS_PER_PATTERN * instrumentID) /* instruments offset */ ; 49 | 50 | // Searching for first active 51 | 52 | unsigned char actives = hwLayer_->readSRAM(instrumentOffset + byteIndex); 53 | 54 | unsigned char nextActives = actives >> bitIndex; 55 | 56 | 57 | while (nextActives == 0) { 58 | bitIndex = 0; 59 | byteIndex = ((byteIndex + 1) % 8); 60 | nextActives = hwLayer_->readSRAM(instrumentOffset + byteIndex); 61 | if (byteIndex == originalByteIndex && nextActives == 0) { 62 | return false; 63 | } 64 | } 65 | 66 | actives = nextActives; 67 | 68 | //Find first non zero bit in the array 69 | while (actives % 2 == 0) { 70 | actives = actives >> 1; 71 | bitIndex++; 72 | } 73 | 74 | step = byteIndex * 8 + bitIndex; 75 | 76 | unsigned char mutes = hwLayer_->readSRAM(instrumentOffset + byteIndex + 8); 77 | unsigned char data = hwLayer_->readSRAM(instrumentOffset + 16 + step); 78 | 79 | bool mute = ((mutes & (1 << bitIndex)) >> bitIndex) == 1; 80 | bool active = ((actives & (1 << bitIndex)) >> bitIndex) == 1; 81 | 82 | DrumStep::DrumVelocityType subSteps[4] = {DrumStep::OFF, DrumStep::OFF, DrumStep::OFF, DrumStep::OFF}; 83 | for (unsigned char i = 0; i < 4; i++) { 84 | subSteps[i] = (DrumStep::DrumVelocityType)(((3 << (i * 2)) & data) >> (i * 2)); 85 | } 86 | 87 | drumStep = DrumStep(mute, subSteps); 88 | return true; 89 | } 90 | 91 | bool FlashStepMemory::setDrumStep(unsigned char instrumentID, unsigned char pattern, unsigned char step, DrumStep stepData) 92 | { 93 | unsigned char byteIndex = step / 8; 94 | unsigned char bitIndex = step % 8; 95 | 96 | long instrumentOffset = (STEPS_PER_PATTERN * INSTRUMENTS * pattern) /* patterbs offset */ + 97 | (STEPS_PER_PATTERN * instrumentID) /* instruments offset */ ; 98 | 99 | unsigned char actives = hwLayer_->readSRAM(instrumentOffset + byteIndex); 100 | unsigned char mutes = hwLayer_->readSRAM(instrumentOffset + byteIndex + 8); 101 | unsigned char data = 0; 102 | 103 | if (stepData.isMuted()) { 104 | mutes = mutes | 1 << bitIndex; 105 | } else { 106 | mutes = mutes & ~(1 << bitIndex); 107 | } 108 | 109 | for (int i = 0; i < 4 ; i++) { 110 | data = (data | stepData.getSubStep(i) << (2 * i)); 111 | } 112 | hwLayer_->writeSRAM(instrumentOffset + byteIndex, actives); 113 | hwLayer_->writeSRAM(instrumentOffset + byteIndex + 8, mutes); 114 | hwLayer_->writeSRAM(instrumentOffset + 16 + step, data); 115 | return true; 116 | } 117 | 118 | void FlashStepMemory::getActivesAndMutesForNote(unsigned char instrumentID, unsigned char pattern, unsigned char windowIndex, unsigned char * data) { 119 | long instrumentOffset = (STEPS_PER_PATTERN * INSTRUMENTS * pattern) /* patterbs offset */ + 120 | (STEPS_PER_PATTERN * instrumentID) /* instruments offset */ ; 121 | 122 | data[0] = hwLayer_->readSRAM(instrumentOffset + windowIndex); 123 | data[1] = hwLayer_->readSRAM(instrumentOffset + windowIndex + 1); 124 | data[2] = hwLayer_->readSRAM(instrumentOffset + windowIndex + 8); 125 | data[3] = hwLayer_->readSRAM(instrumentOffset + windowIndex + 9); 126 | } 127 | 128 | void FlashStepMemory::getPatternSettings(unsigned char patternIndex, unsigned char * settings) { 129 | hwLayer_->readSRAM( DRUM_BYTES + patternIndex * 3, settings, 3); 130 | } 131 | void FlashStepMemory::setPatternSettings(unsigned char patternIndex, unsigned char * settings) { 132 | hwLayer_->writeSRAM( DRUM_BYTES + patternIndex * 3, settings, 3); 133 | } 134 | 135 | -------------------------------------------------------------------------------- /eepromObject.h: -------------------------------------------------------------------------------- 1 | /* 2 | * eepromObject.h 3 | * 4 | * Created on: 03.07.2014 5 | * Author: user 6 | */ 7 | 8 | #ifndef EEPROMOBJECT_H_ 9 | #define EEPROMOBJECT_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | 17 | /* 18 | Base class for the EEPROMObject class 19 | It's only purpose is to track the position of the last bit in EEPROM that is managed by EEPROMObject 20 | @note: There is no constructor implemented to prevent the creation of instances 21 | */ 22 | 23 | class EEPROMBaseObject { 24 | 25 | protected: 26 | static uint16_t totalSize; 27 | }; 28 | 29 | uint16_t EEPROMBaseObject::totalSize = 0; 30 | 31 | 32 | 33 | /* 34 | Class that allows to pack subsets of bits of POD data types into EEPROM 35 | In order to use every bit of EEPROM memory, variables need to concatenated. Further more, if a variable is limited to a maximum value smaller that the maximum value of the data type, 36 | only the bits can be stored. 37 | Every instance contains a public member VALUE that serves as a buffer for that variable in RAM. With store() and load(), this buffer is written to EEPROM. 38 | @note A boundary check is not performed. Values that are greater than the range provided by the number of stored bits will be clipped! 39 | */ 40 | 41 | 42 | template 43 | class EEPROMObject : public EEPROMBaseObject { 44 | 45 | public: 46 | // default constructor. should not be called! 47 | //EEPROMObject(); 48 | 49 | // create object. eeprom is not accessed 50 | EEPROMObject(uint8_t numBits); 51 | 52 | // write the buffer to the eeprom 53 | void store(); 54 | 55 | //shortcut to set RAM buffer and write to EEPROM 56 | void store(baseType value); 57 | 58 | // reads the value from eeprom the buffer and returns it 59 | baseType load(); 60 | 61 | // the buffer of the actual value. can be modified independent from eeprom memory 62 | // allowing this direct access can save one external variable 63 | baseType value; 64 | 65 | // buffer for the default value. read and write directly 66 | baseType defaultValue; 67 | 68 | private: 69 | 70 | uint8_t storedBits; // the number of bits that are actually used in EEPROM. this of course limits the maximum size of the storable value 71 | uint16_t offset; // index of the first bit in eeprom that belongs to this object 72 | 73 | }; 74 | 75 | 76 | 77 | template 78 | EEPROMObject::EEPROMObject(uint8_t numBits) { 79 | storedBits = numBits; 80 | offset = totalSize; // start at next unused bit 81 | totalSize += storedBits; // increase the total size of all concatenated eeprom objects 82 | defaultValue = 0; 83 | } 84 | 85 | 86 | template 87 | void EEPROMObject::store(baseType writeValue) { 88 | value = writeValue; 89 | store(); 90 | } 91 | 92 | 93 | template 94 | void EEPROMObject::store() { 95 | uint16_t posEEPROM = offset; // position of bit in eeprom 96 | 97 | DBGS Serial.print("Saving "); Serial.print(value); Serial.print(" at "); Serial.println(posEEPROM); DBGE 98 | 99 | // get the first affected byte 100 | uint8_t eepromByte = EEPROM.read(posEEPROM/8); 101 | 102 | DBGS Serial.print("Read Byte: "); Serial.println(eepromByte,BIN); DBGE 103 | 104 | //go through the bits that should be written to eeprom 105 | for (uint8_t numBit = storedBits; numBit>0; numBit--) { //form X to 1 MSB-->LSB 106 | 107 | DBGS Serial.print("Storing bit "); Serial.println(numBit,DEC); DBGE 108 | 109 | bool bitValueToWrite = bitRead(value,numBit-1); 110 | uint8_t posInTargetByte = (7 - posEEPROM % 8); 111 | 112 | DBGS Serial.println(bitValueToWrite); DBGE 113 | DBGS Serial.println(posInTargetByte); DBGE 114 | 115 | bitWrite(eepromByte,posInTargetByte,bitValueToWrite); //modify bit in EEPROM byte 116 | 117 | posEEPROM++; // move reading head 118 | 119 | if (posEEPROM % 8 == 0) { // if border to new byte is crossed 120 | EEPROM.write((posEEPROM-1)/8,eepromByte); // save modified byte to eeprom 121 | eepromByte = EEPROM.read(posEEPROM/8); // ..and get the next byte 122 | DBGS Serial.print("Reading next byte : "); Serial.println(eepromByte,BIN); DBGE 123 | } 124 | } 125 | 126 | EEPROM.write(posEEPROM/8, eepromByte); //save modifications on eeprom byte 127 | 128 | } 129 | 130 | template 131 | baseType EEPROMObject::load() { 132 | 133 | uint16_t readPos = offset; 134 | 135 | DBGS Serial.print("Reading "); Serial.print(storedBits); Serial.print(" bits from "); Serial.println(offset); DBGE 136 | 137 | //get the first affected byte 138 | uint8_t eepromByte = EEPROM.read(readPos/8); 139 | 140 | DBGS Serial.print("Read Byte: "); Serial.println(eepromByte,BIN); DBGE 141 | 142 | // clear value 143 | value = 0; 144 | 145 | // go through all the stored bits 146 | for (uint8_t numBit = storedBits; numBit>0; numBit--) { 147 | 148 | DBGS Serial.print("Reading bit "); Serial.println(numBit,DEC); DBGE 149 | 150 | bool bitValueToRead = bitRead(eepromByte,7-(readPos%8)); //reading the bit that readPos is pointing at 151 | bitWrite(value,numBit-1,bitValueToRead); 152 | 153 | readPos++; // move bit pointer one step ahead 154 | 155 | if (readPos % 8 == 0) { //if border to new byte has been crossed 156 | eepromByte = EEPROM.read(readPos/8); 157 | DBGS Serial.print("Reading next byte : "); Serial.println(eepromByte,BIN); DBGE 158 | } 159 | } 160 | 161 | return value; 162 | } 163 | 164 | 165 | 166 | 167 | #endif /* EEPROMOBJECT_H_ */ 168 | -------------------------------------------------------------------------------- /NoVelocityStepMemory.cpp: -------------------------------------------------------------------------------- 1 | #include "NoVelocityStepMemory.h" 2 | #include "BitArrayOperations.h" 3 | 4 | #define INSTRUMENT_DATA_OFFSET 5 | 6 | //#define DEBUG 7 | #ifdef DEBUG 8 | 9 | #include 10 | 11 | #endif 12 | 13 | NoVelocityStepMemory::NoVelocityStepMemory() 14 | { 15 | } 16 | 17 | NoVelocityStepMemory::~NoVelocityStepMemory() 18 | { 19 | } 20 | 21 | void NoVelocityStepMemory::getDrumStepDataPointers(unsigned char instrumentID, unsigned char step, 22 | unsigned char *& mutes, unsigned char *& data) { 23 | 24 | unsigned int offset = getDataOffset(instrumentID, step / 16); 25 | 26 | mutes = &data_[offset + (step / 8) % 2]; 27 | data = &data_[offset + 2 + ((step % 16) / 2)]; 28 | } 29 | 30 | DrumStep NoVelocityStepMemory::getDrumStep(unsigned char instrumentID, unsigned char step) 31 | { 32 | unsigned char * data; 33 | unsigned char * mutes; 34 | 35 | unsigned char bitIndex = step % 8; 36 | getDrumStepDataPointers(instrumentID, step, mutes, data); 37 | 38 | DrumStep::DrumVelocityType subSteps[4]; 39 | for (unsigned char i = 0; i < 4; i++) { 40 | unsigned char offset = ((step % 2) * 4) + i; 41 | #ifdef DEBUG 42 | bool bitAtPosition = BitArrayOperations::getBit(* data, offset); 43 | printf("Getting bit at index %d to value %s \n", offset, bitAtPosition ? "True": "False"); 44 | #endif 45 | subSteps[i] = getBit(* data, offset) ? DrumStep::NORMAL : DrumStep::OFF; 46 | } 47 | return DrumStep(getBit(* mutes, bitIndex), subSteps); 48 | } 49 | 50 | bool NoVelocityStepMemory::getNextActiveDrumStep(unsigned char instrumentID, unsigned char &step, DrumStep &drumStep) 51 | { 52 | unsigned char activeSteps = getNumberOfActives(instrumentID); 53 | if (activeSteps != 0) { 54 | step = step % activeSteps; 55 | drumStep = getDrumStep(instrumentID, step); 56 | return true; 57 | 58 | } else { 59 | return false; 60 | } 61 | } 62 | 63 | bool NoVelocityStepMemory::setDrumStep(unsigned char instrumentID, unsigned char step, DrumStep stepData) 64 | { 65 | unsigned char * mutes; 66 | unsigned char * data; 67 | 68 | unsigned char bitIndex = step % 8; 69 | 70 | getDrumStepDataPointers(instrumentID, step, mutes, data); 71 | 72 | setBit(*mutes, bitIndex, stepData.isMuted()); 73 | unsigned char offset = ((step % 2) * 4); 74 | for (int i = 0; i < 4 ; i++) { 75 | setBit(*data, offset + i, stepData.getSubStep(i) == DrumStep::NORMAL); 76 | #ifdef DEBUG 77 | //printf("Setting bit at index %d to value %s \n", offset, stepData.getSubStep(i) == DrumStep::NORMAL ? "True": "False"); 78 | #endif 79 | } 80 | return true; 81 | } 82 | 83 | void NoVelocityStepMemory::getMutesForNote(unsigned char instrumentID, unsigned char windowIndex, unsigned char *& data) { 84 | 85 | unsigned int offset = getDataOffset(instrumentID, windowIndex); 86 | data = &data_[offset]; 87 | } 88 | 89 | void NoVelocityStepMemory::getAllInstrumentActivesFor16Steps(unsigned char fromIndex, ActiveMultiStatus * result) { 90 | for (unsigned char step = 0; step < 16; step++) { 91 | unsigned char actives = 0; 92 | unsigned char inactives = 0; 93 | for (unsigned char instrument = 0; instrument < 6; instrument++) { 94 | if (step < getNumberOfActives(instrument)) { 95 | actives++; 96 | } else { 97 | inactives++; 98 | } 99 | } 100 | if (actives == 0) { 101 | result[step] = ALLINACTIVE; 102 | } else if (inactives == 0) { 103 | result[step] = ALLACTIVE; 104 | } else { 105 | result[step] = MIXED; 106 | } 107 | } 108 | } 109 | 110 | void NoVelocityStepMemory::makeActiveUpTo(unsigned char instrument, unsigned char indexUpTo) { 111 | indexUpTo++; 112 | unsigned int instrumentOffset = (unsigned int)instrument * (unsigned int)48; 113 | for (unsigned char i = 0; i < 8; i++) { 114 | unsigned int offset = instrumentOffset + (((i / 2) * 12) + (i % 2)); 115 | data_[offset] = 0; 116 | for (unsigned char j = 0; j < 8; j++) { 117 | if (indexUpTo > 0) { 118 | data_[offset] |= (1 << j); 119 | indexUpTo--; 120 | } 121 | } 122 | } 123 | } 124 | 125 | void NoVelocityStepMemory::makeAllInstrumentsActiveUpTo(unsigned char indexUpTo) { 126 | for (unsigned char instrument = 0; instrument < 6; instrument++) { 127 | makeActiveUpTo(instrument, indexUpTo); 128 | } 129 | 130 | } 131 | 132 | void NoVelocityStepMemory::clearStepsForInstrument(unsigned char instrument) { 133 | for (unsigned char step = 0; step < 64; step++) { 134 | DrumStep stepData = getDrumStep(instrument, step); 135 | stepData.setMuted(true); 136 | for (unsigned char substep = 0; substep < 4; substep++) { 137 | stepData.setSubStep(substep, DrumStep::OFF); 138 | } 139 | setDrumStep(instrument, step, stepData); 140 | } 141 | } 142 | 143 | void NoVelocityStepMemory::clearStepsForAllInstruments() { 144 | for (unsigned char instrument = 0; instrument < 6; instrument++) { 145 | clearStepsForInstrument(instrument); 146 | } 147 | } 148 | 149 | unsigned char NoVelocityStepMemory::getNumberOfActives(unsigned char instrument) { 150 | unsigned char numberOfActives = 0; 151 | unsigned int instrumentOffset = (unsigned int)instrument * (unsigned int)48; 152 | for (unsigned char i = 0; i < 8; i++) { 153 | unsigned int offset = ((i / 2) * 12) + (i % 2); 154 | unsigned char data = data_[instrumentOffset + offset]; 155 | for (unsigned char dataIndex = 0; dataIndex < 8; dataIndex++) { 156 | numberOfActives += (data & (1 << dataIndex)) != 0 ? 1 : 0; 157 | } 158 | } 159 | return numberOfActives; 160 | } 161 | 162 | unsigned int NoVelocityStepMemory::getDataOffset(unsigned char instrumentID, unsigned char pan) { 163 | // 64 steps, bits per step = 384 bits = 48 bytes 164 | return ((unsigned int)instrumentID * 48) + 165 | ((unsigned int)pan * 12) + 2; 166 | } 167 | -------------------------------------------------------------------------------- /test/data/lfo.plt: -------------------------------------------------------------------------------- 1 | reset 2 | set zeroaxis 3 | set key right bottom 4 | set xlabel "number of time units" 5 | set ylabel "lfo output" 6 | 7 | set ytics 64 8 | #set mytics 16 9 | 10 | set grid ytics mytics 11 | #set xtics out 100 12 | #set mxtics 10 13 | 14 | set key top center outside 15 | 16 | set terminal pdfcairo 17 | set output "LFO.pdf" 18 | 19 | 20 | set title "Frequency" 21 | plot 'Freq1' with lines title col,'Freq2' with lines title col, 'Freq3' with lines title col 22 | 23 | set title "Waveform" 24 | plot 'Waveform1' with lines title col,'Waveform2' with lines title col,'Waveform3' with lines title col 25 | 26 | set title "Resolution" 27 | plot 'Res0' with lines title col,\ 28 | 'Res1' with lines title col,\ 29 | 'Res2' with lines title col,\ 30 | 'Res3' with lines title col,\ 31 | 'Res4' with lines title col,\ 32 | 'Res5' with lines title col,\ 33 | 'Res6' with lines title col,\ 34 | 'Res7' with lines title col 35 | 36 | 37 | set title "Smoothness" 38 | plot 'Smooth0' with lines title col,\ 39 | 'Smooth50' with lines title col,\ 40 | 'Smooth100' with lines title col,\ 41 | 'Smooth150' with lines title col,\ 42 | 'Smooth200' with lines title col,\ 43 | 'Smooth250' with lines title col 44 | 45 | set title "Smoothness Low" 46 | plot 'Smooth0' with lines title col,\ 47 | 'Smooth5' with lines title col,\ 48 | 'Smooth10' with lines title col,\ 49 | 'Smooth15' with lines title col,\ 50 | 'Smooth20' with lines title col,\ 51 | 'Smooth25' with lines title col 52 | 53 | set title "Flopping" 54 | plot 'Flop0' with lines title col,\ 55 | 'Flop1' with lines title col,\ 56 | 'Flop2' with lines title col,\ 57 | 'Flop3' with lines title col,\ 58 | 'Flop4' with lines title col,\ 59 | 'Flop5' with lines title col,\ 60 | 'Flop6' with lines title col,\ 61 | 'Flop7' with lines title col 62 | 63 | 64 | set title "Flopping Random" 65 | plot 'FlopRand0' with lines title col,\ 66 | 'FlopRand1' with lines title col,\ 67 | 'FlopRand2' with lines title col,\ 68 | 'FlopRand3' with lines title col,\ 69 | 'FlopRand4' with lines title col,\ 70 | 'FlopRand5' with lines title col,\ 71 | 'FlopRand6' with lines title col,\ 72 | 'FlopRand7' with lines title col 73 | 74 | 75 | set title "XOR" 76 | plot 'Xor0' with lines title col,\ 77 | 'Xor1' with lines title col,\ 78 | 'Xor2' with lines title col,\ 79 | 'Xor3' with lines title col,\ 80 | 'Xor4' with lines title col,\ 81 | 'Xor5' with lines title col,\ 82 | 'Xor6' with lines title col,\ 83 | 'Xor7' with lines title col 84 | 85 | 86 | set title "XOR Random" 87 | plot 'XorRand0' with lines title col,\ 88 | 'XorRand1' with lines title col,\ 89 | 'XorRand2' with lines title col,\ 90 | 'XorRand3' with lines title col,\ 91 | 'XorRand4' with lines title col,\ 92 | 'XorRand5' with lines title col,\ 93 | 'XorRand6' with lines title col,\ 94 | 'XorRand7' with lines title col 95 | 96 | set title "Folding" 97 | plot 'Fold0' with lines title col,\ 98 | 'Fold1' with lines title col,\ 99 | 'Fold2' with lines title col,\ 100 | 'Fold3' with lines title col,\ 101 | 'Fold4' with lines title col,\ 102 | 'Fold5' with lines title col,\ 103 | 'Fold6' with lines title col,\ 104 | 'Fold7' with lines title col 105 | 106 | 107 | set title "Folding Random" 108 | plot 'FoldRand0' with lines title col,\ 109 | 'FoldRand1' with lines title col,\ 110 | 'FoldRand2' with lines title col,\ 111 | 'FoldRand3' with lines title col,\ 112 | 'FoldRand4' with lines title col,\ 113 | 'FoldRand5' with lines title col,\ 114 | 'FoldRand6' with lines title col,\ 115 | 'FoldRand7' with lines title col 116 | 117 | set title "Overflow" 118 | plot 'Overflow0' with lines title col,\ 119 | 'Overflow1' with lines title col,\ 120 | 'Overflow2' with lines title col,\ 121 | 'Overflow3' with lines title col,\ 122 | 'Overflow4' with lines title col,\ 123 | 'Overflow5' with lines title col,\ 124 | 'Overflow6' with lines title col,\ 125 | 'Overflow7' with lines title col 126 | 127 | 128 | set title "Overflow Random" 129 | plot 'OverflowRand0' with lines title col,\ 130 | 'OverflowRand1' with lines title col,\ 131 | 'OverflowRand2' with lines title col,\ 132 | 'OverflowRand3' with lines title col,\ 133 | 'OverflowRand4' with lines title col,\ 134 | 'OverflowRand5' with lines title col,\ 135 | 'OverflowRand6' with lines title col,\ 136 | 'OverflowRand7' with lines title col 137 | 138 | #set title "Overflow" 139 | #plot for [col=2:5] 'lfoTimeOverflow.csv' using 1:col with lines title col 140 | 141 | 142 | #set title "Waveforms" 143 | #plot for [col=2:5] 'lfoWaveforms.csv' using 1:col with lines title col 144 | 145 | 146 | #set title "Resolution" 147 | #plot for [col=2:5] 'lfoResolution.csv' using 1:col with lines title col 148 | 149 | #set title "XOR" 150 | #plot for [col=2:5] 'lfoXOR.csv' using 1:col with lines title col 151 | 152 | #set title "Flop" 153 | #plot for [col=2:5] 'lfoFlop.csv' using 1:col with lines title col 154 | 155 | #set title "Threshold" 156 | #plot for [col=2:5] 'lfoThres.csv' using 1:col with lines title col 157 | 158 | #set title "Random" 159 | #plot for [col=2:5] 'lfoRandom.csv' using 1:col with lines title col 160 | 161 | #set title "set step" 162 | #plot for [col=2:5] 'lfoSetStep.csv' using 1:col with lines title col 163 | 164 | 165 | 166 | 167 | 168 | #set y2tics 10000 169 | 170 | #set terminal pdfcairo 171 | #set output "lfoInternal.pdf" 172 | 173 | #plot for [col=2:4] 'lfoInternal.csv' using 1:col with lines title col axes x1y2 lw 2,\ 174 | # for [col=5:6] 'lfoInternal.csv' using 1:col with lines title col axes x1y1 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /players/test/tst.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../PlayerSettings.h" 3 | #include "../Player.h" 4 | #include "../../data/InstrumentDefinitions.h" 5 | #include "../../data/test/DummyStepMemory.h" 6 | #include "MIDICommandProcessorMock.h" 7 | 8 | int main( int argc, const char* argv[] ) { 9 | PlayerSettings settings; 10 | printf("Testing PlayerSettings\n"); 11 | 12 | settings.setInstrumentChannel(InstrumentTypes::DRUM, 19, 0); 13 | printf("\tTest 1 - Set DRUM instrument channel \t\t%s\n", settings.getInstrumentChannel(InstrumentTypes::DRUM, 10) == 0 ? "OK" : "Error"); 14 | settings.setInstrumentChannel(InstrumentTypes::MONO, 3, 15); 15 | printf("\tTest 2 - Set MONO instrument channel \t\t%s\n", settings.getInstrumentChannel(InstrumentTypes::MONO, 2) == 15 ? "OK" : "Error"); 16 | settings.setDrumInstrumentNote(19, 120); 17 | printf("\tTest 3 - Set DRUM instrument note \t\t%s\n", settings.getDrumInstrumentNote(19) == 120 ? "OK" : "Error"); 18 | 19 | printf("\tTest 4 - Default DRUM instrument status \t\t%s\n", settings.isInstrumentOn(InstrumentTypes::DRUM, 19) ? "OK" : "Error"); 20 | printf("\tTest 5 - Default MONO instrument status \t\t%s\n", settings.isInstrumentOn(InstrumentTypes::MONO, 0) ? "OK" : "Error"); 21 | 22 | settings.setInstrumentOn(InstrumentTypes::DRUM, 19, false); 23 | printf("\tTest 6 - Set DRUM instrument status \t\t%s\n", settings.isInstrumentOn(InstrumentTypes::DRUM, 19) ? "Error" : "OK"); 24 | 25 | settings.setInstrumentOn(InstrumentTypes::MONO, 0, false); 26 | printf("\tTest 7 - Set MONO instrument status \t\t%s\n", settings.isInstrumentOn(InstrumentTypes::MONO, 0) ? "Error" : "OK"); 27 | 28 | settings.setMIDIVelocitiesForDrumVelocities(10, 20, 30); 29 | printf("\tTest 8 - Set map DRUM to MIDI velocities (Up) \t\t%s\n", settings.getMIDIVelocityFromDrumVelocity(DrumStep::UP) == 10 ? "OK" : "Error"); 30 | printf("\tTest 9 - Set map DRUM to MIDI velocities (Down) \t\t%s\n", settings.getMIDIVelocityFromDrumVelocity(DrumStep::DOWN) == 20 ? "OK" : "Error"); 31 | printf("\tTest 10 - Set map DRUM to MIDI velocities (Normal) \t\t%s\n", settings.getMIDIVelocityFromDrumVelocity(DrumStep::NORMAL) == 30 ? "OK" : "Error"); 32 | 33 | printf("\nTesting MIDI command processor MOCK\n"); 34 | MIDICommandProcessorMock mock; 35 | printf("\tTest 11 - Checking initialized On counters \t\t%s\n", mock.getNoteOffCountForChannel(5) == 0 ? "OK" : "Error"); 36 | printf("\tTest 12 - Checking initialized Off counters \t\t%s\n", mock.getNoteOnCountForChannel(10) == 0 ? "OK" : "Error"); 37 | MIDICommand onCommand(MIDICommand::NOTEON, 0, 0, 0); 38 | onCommand.setChannel(10); 39 | MIDICommand offCommand(MIDICommand::NOTEOFF, 0, 0, 0); 40 | offCommand.setChannel(5); 41 | mock.SendCommand(onCommand); 42 | mock.SendCommand(onCommand); 43 | mock.SendCommand(offCommand); 44 | printf("\tTest 13 - Checking used On counters \t\t%s\n", mock.getNoteOffCountForChannel(5) == 1 ? "OK" : "Error"); 45 | printf("\tTest 14 - Checking used Off counters \t\t%s\n", mock.getNoteOnCountForChannel(10) == 2 ? "OK" : "Error"); 46 | mock.clear(); 47 | printf("\tTest 15 - Checking cleared On counters \t\t%s\n", mock.getNoteOffCountForChannel(5) == 0 ? "OK" : "Error"); 48 | printf("\tTest 16 - Checking cleared Off counters \t\t%s\n", mock.getNoteOnCountForChannel(10) == 0 ? "OK" : "Error"); 49 | 50 | 51 | printf("\nTesting Player\n"); 52 | 53 | DummyStepMemory stepMemory; 54 | DrumStep::DrumVelocityType substeps[4] = {DrumStep::NORMAL, DrumStep::OFF, DrumStep::OFF, DrumStep::OFF}; 55 | DrumStep::DrumVelocityType substeps2[4] = {DrumStep::OFF, DrumStep::OFF, DrumStep::OFF, DrumStep::OFF}; 56 | //DrumStep::DrumVelocityType substeps3[4] = {DrumStep::NORMAL, DrumStep::OFF, DrumStep::OFF, DrumStep::NORMAL}; 57 | for (int i = 0; i < 8; i++) { 58 | stepMemory.setDrumStep(0, 0, i, DrumStep(true, false, substeps)); 59 | } 60 | for (int i = 8; i < 64; i++) { 61 | stepMemory.setDrumStep(0, 0, i, DrumStep(false, false, substeps2)); 62 | } 63 | //stepMemory.setDrumStep(1, 0, 1, DrumStep(false, false, substeps2)); 64 | //stepMemory.setDrumStep(1, 0, 2, DrumStep(true, true, substeps2)); 65 | //stepMemory.setDrumStep(1, 0, 3, DrumStep(true, false, substeps3)); 66 | Player player(& stepMemory, & mock, & settings); 67 | 68 | //First step 69 | for (int i = 0; i < 64; i++) { 70 | player.stepFourth(); 71 | /*printf(" %d NOTE ONs: %d NOTE OFFs %d Curent step: %d\n", 72 | i, 73 | mock.getNoteOnCountForChannel(0), 74 | mock.getNoteOffCountForChannel(0), 75 | player.getCurrentInstrumentStep(0));*/ 76 | } 77 | 78 | printf("\tTest 17 - Two instruments playing one step \t\t%s\n", mock.getNoteOnCountForChannel(0) == 6 && 79 | mock.getNoteOffCountForChannel(0) == 4 ? "OK" : "Error"); 80 | 81 | //Second step is disactivated playing third that is empty 82 | player.stepFourth(); 83 | player.stepFourth(); 84 | player.stepFourth(); 85 | player.stepFourth(); 86 | 87 | printf("\tTest 18 - One inactive + one muted \t\t%s\n", mock.getNoteOnCountForChannel(0) == 6 && 88 | mock.getNoteOffCountForChannel(0) == 6 ? "OK" : "Error"); 89 | 90 | //Playing fourth 91 | player.stepFourth(); 92 | player.stepFourth(); 93 | player.stepFourth(); 94 | player.stepFourth(); 95 | 96 | printf("\tTest 20 - Next one substep to noteOff \t\t%s\n", mock.getNoteOnCountForChannel(0) == 8 && 97 | mock.getNoteOffCountForChannel(0) == 7 ? "OK" : "Error"); 98 | 99 | player.stepFourth(); 100 | 101 | printf("\tTest 19 - Next one active step \t\t%s\n", mock.getNoteOnCountForChannel(0) == 8 && 102 | mock.getNoteOffCountForChannel(0) == 8 ? "OK" : "Error"); 103 | } 104 | --------------------------------------------------------------------------------