├── MEM.ino ├── MIDI.ino ├── SD.ino ├── SOUND.ino ├── UI.ino ├── fileNames.ino └── microGranny2.ino /MEM.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | PROGMEM prog_uint16_t clearTo[]={ 4 | 877, 0, 0,0, 0,128,0,1022, 13 , 65,48}; 5 | /* 6 | //13 = 1011 - sync ON, shiftDir OFF,tuned ON,repeat ON, 7 | 8 | red 9 | sampleRate, crush, start, end // loop 10 | 11 | green 12 | loopLen, shift, attack, release // normal-random 13 | 14 | blue 15 | rate, amt, shape, resolution // dest 16 | 17 | */ 18 | 19 | // variable names 20 | //page 0 21 | 22 | 23 | //osc mod-freq amt 24 | //atck decay mod type // 2+2+3 25 | 26 | #define PAGE_G 0 27 | #define PAGE_B 1 28 | 29 | 30 | #define VARIABLES_PER_PAGE 4 31 | PROGMEM prog_char labels[]={ 32 | "rcargmse"}; 33 | 34 | #define RATE 0 //1024 - 10 R 35 | #define CRUSH 1 //127 - 7 C 36 | 37 | #define ATTACK 2 // 127 - 7 A 38 | #define RELEASE 3 // 127 - 7 R 39 | 40 | 41 | // =41 42 | #define LOOP_LENGTH 4 // 127 - 7 L 43 | #define SHIFT_SPEED 5 // 127 - 7 S 44 | 45 | #define START 6 //1024 - 10 S 46 | #define END 7 //1024 - 10 E 47 | 48 | 49 | 50 | //#define MODE 8 // 1 - 1 M 51 | 52 | #define SETTING 8 // 7 - 4 L 53 | // = 29 54 | #define SAMPLE_NAME_1 9 // 127 - 7 55 | #define SAMPLE_NAME_2 10 // 127 - 7 56 | //#define SAMPLE_NAME_3 12 // 127 - 7 57 | // = 14 58 | 59 | /* 60 | #define LFO_RATE 10 // 127 -7 R 61 | #define LFO_AMT 11 // 127 -7 A 62 | #define LFO_SHAPE 12 // 7 -3 S 63 | #define LFO_RES 13 // 15 - 4 R 64 | #define LFO_DEST 14 // 3 -2 D 65 | */ 66 | // =23 67 | 68 | 69 | 70 | 71 | 72 | // 41+29+14 = 84 /8 = 10,5 =>11 73 | 74 | 75 | #define KNOB_BITS 10 76 | 77 | 78 | PROGMEM prog_uint16_t maxValue[]={ 79 | 1023,127,127,127, 127,255,1023,1023,63 ,127,127}; //const //127,127,7,15,3 80 | 81 | 82 | #define NUMBER_OF_VARIABLES 11 83 | 84 | #define NUMBER_OF_BYTES 12 //11 85 | #define NUMBER_OF_PRESETS 6 86 | #define NUMBER_OF_BANKS 9 87 | 88 | #define PRESET_SIZE 84 //66 in real 89 | 90 | #define NUMBER_OF_SOUNDS 6 91 | 92 | #define CHANNEL_BYTE 1023 93 | 94 | 95 | const unsigned char variableDepth[NUMBER_OF_VARIABLES]={ 96 | 10,7,7,7, 7,8,10,10,8, 7,7}; 97 | 98 | 99 | 100 | int maxVal(int _maxVal){ 101 | return pgm_read_word_near(maxValue+_maxVal); 102 | } 103 | 104 | const unsigned char byteCoordinate[NUMBER_OF_VARIABLES]={ 105 | 0, 1, 2, 3, 3, 4, 5, 7, 8, 9, 10} 106 | ; 107 | 108 | /* 109 | unsigned char byteCoordinate[NUMBER_OF_VARIABLES]={ 110 | 0, 2, 3, 4, 5, 6, 7, 9, 11, 12, 13} 111 | ; 112 | */ 113 | 114 | const unsigned char bitCoordinate[NUMBER_OF_VARIABLES]={ 115 | 0, 2, 1, 0, 7, 6, 6, 0, 2, 2, 1}; 116 | 117 | 118 | /* 119 | int buffer[NUMBER_OF_SOUNDS][NUMBER_OF_VARIABLES]; 120 | unsigned char bufferP[NUMBER_OF_STEPS]; 121 | */ 122 | 123 | unsigned char variable[NUMBER_OF_SOUNDS][NUMBER_OF_BYTES]; 124 | /* 125 | unsigned char variableCop[NUMBER_OF_SOUNDS][NUMBER_OF_BYTES]; 126 | void copyPreset(){ 127 | for(int i=0;i=0) x++; 151 | variableDepth[i]=x ; 152 | } 153 | */ 154 | /* 155 | for(int i=0;i15){ 177 | byteShift=2; 178 | _bitCoordinate = i-(16-bitCoordinate[_VARIABLE]); 179 | } 180 | else if((bitCoordinate[_VARIABLE]+i)>7){ 181 | byteShift=1; 182 | _bitCoordinate = i-(8-bitCoordinate[_VARIABLE]);//bitCount; 183 | } 184 | else { 185 | _bitCoordinate=bitCoordinate[_VARIABLE]+i; 186 | } 187 | 188 | boolean bitState=bitRead(variable[_SOUND][byteCoordinate[_VARIABLE]+byteShift],_bitCoordinate); 189 | bitWrite(_value,i,bitState); 190 | 191 | } 192 | return _value; 193 | 194 | 195 | } 196 | 197 | void setVar(unsigned char _SOUND, unsigned char _VARIABLE, int _value){ 198 | 199 | unsigned char byteShift=0; 200 | unsigned char _bitCoordinate; 201 | for(int i=0;i15){ 206 | byteShift=2; 207 | _bitCoordinate = i-(16-bitCoordinate[_VARIABLE]); 208 | } 209 | else if((bitCoordinate[_VARIABLE]+i)>7){ 210 | byteShift=1; 211 | _bitCoordinate = i-(8-bitCoordinate[_VARIABLE]); 212 | } 213 | else { 214 | _bitCoordinate=bitCoordinate[_VARIABLE]+i; 215 | } 216 | 217 | boolean bitState=bitRead(_value,i); 218 | bitWrite(variable[_SOUND][byteCoordinate[_VARIABLE]+byteShift],_bitCoordinate,bitState); 219 | } 220 | 221 | } 222 | 223 | char presetName[8]="p00.txt"; 224 | boolean storePreset(unsigned char _bank,unsigned char _preset) { 225 | // Serial.end(); 226 | // Serial.begin(9600); 227 | noSound(); 228 | //clearBuffer(); 229 | presetName[2]=_preset+49; 230 | presetName[1]=_bank+48; 231 | 232 | if (!file.open(&root,presetName, O_WRITE | O_CREAT)) { 233 | return false; 234 | } 235 | for (int j = 0; j < NUMBER_OF_SOUNDS; j++) { 236 | for (int k = 0; k < NUMBER_OF_BYTES; k++) { 237 | file.write(variable[j][k]); 238 | } 239 | } 240 | 241 | file.close(); 242 | 243 | // clearIndexes(); 244 | return true; 245 | } 246 | 247 | void loadPreset(unsigned char _bank,unsigned char _preset) { 248 | 249 | if(_preset>=NUMBER_OF_PRESETS) _preset=NUMBER_OF_PRESETS-1; 250 | if(_bank>=200) _bank=0; 251 | if(_bank>=NUMBER_OF_BANKS) _bank=NUMBER_OF_BANKS; 252 | //if(_bank<=0) _bank=0; 253 | 254 | presetName[2]=_preset+49; 255 | presetName[1]=_bank+48; 256 | 257 | currentPreset=_preset; 258 | currentBank=_bank; 259 | 260 | noSound(); 261 | clearBuffer(); 262 | if(!file.open(&root, presetName, O_READ)){ 263 | clearPreset(); 264 | storePreset(_bank,_preset); 265 | file.open(&root, presetName, O_READ); 266 | } 267 | 268 | for (int j = 0; j < NUMBER_OF_SOUNDS; j++) { 269 | for (int k = 0; k < NUMBER_OF_BYTES; k++) { 270 | variable[j][k]=file.read(); 271 | } 272 | } 273 | file.close(); 274 | hw.freezeAllKnobs(); 275 | showForWhile("pr "),hw.setDot(1,true),hw.displayChar(presetName[2],3),hw.displayChar(presetName[1],2), clearIndexes(); 276 | } 277 | 278 | 279 | 280 | void clearMemmory(){ 281 | for(int i=0;i=val2){ 307 | if(inBet<=val1 && inBet>=val2) retVal=true; 308 | else retVal=false; 309 | } 310 | else if(val1=val1 && inBet<=val2) retVal=true; 312 | else retVal=false; 313 | } 314 | 315 | return retVal; 316 | 317 | } 318 | 319 | int scale(int _value, unsigned char _originalBits, unsigned char _endBits){ 320 | if(_originalBits >= _endBits) return _value >> (_originalBits - _endBits); 321 | else return _value << (_endBits - _originalBits); 322 | } 323 | 324 | 325 | 326 | long myMap(long x, long in_max, long out_max) 327 | { 328 | return (x) * (out_max) / (in_max); 329 | } 330 | 331 | 332 | -------------------------------------------------------------------------------- /MIDI.ino: -------------------------------------------------------------------------------- 1 | // op qr st uv wx yz 2 | unsigned char incomingByte,note; 3 | boolean ignore, comandOff,slave,cc; //,midiNoteOn noteOn, 4 | unsigned char state=0; 5 | unsigned char channel=0; 6 | int clockCounter; 7 | #define MIDI_CHANNEL 1023 8 | #define POLYPHONY NUMBER_OF_VOICES 9 | unsigned char notesInBuffer=ZERO; 10 | boolean thereIsNoteToPlay; 11 | unsigned char sound, activeSound; 12 | 13 | #define BUFFER_SIZE 16 14 | unsigned char midiBuffer[BUFFER_SIZE]; 15 | #define EMPTY 255 16 | unsigned char midiVelocity; 17 | unsigned char fromBuffer; 18 | unsigned char instantLoop; 19 | boolean sustain; 20 | boolean legato; 21 | unsigned char channelSide=0; 22 | unsigned char sideNote=1; 23 | unsigned char sideDecay; 24 | //int pitchBendNow; 25 | int sampleRateNow; 26 | unsigned char setting; 27 | int attackInterval, releaseInterval; 28 | //long legatoPosition; 29 | PROGMEM prog_uint16_t noteSampleRateTable[49]={/*0-C*/ 30 | 2772,2929,3103,3281,3500,3679,3910,4146,4392,4660,4924,5231,5528,5863,6221,6579,6960,7355,7784,8278,8786,9333,9847,10420,11023,11662,12402,13119,13898,14706,15606,16491,17550,18555,19677,20857,22050,23420,24807,26197,27815,29480,29480,29480,29480,29480,29480,29480,/*48-C*/29480}; 31 | 32 | 33 | void shiftBufferLeft(unsigned char from){ 34 | for(int i=from;iZERO;i--){ 41 | midiBuffer[i]=midiBuffer[i-1]; 42 | } 43 | } 44 | 45 | boolean isThereNoteToPlay(){ 46 | return thereIsNoteToPlay; 47 | 48 | } 49 | unsigned char noteToPlay(){ 50 | thereIsNoteToPlay=false; 51 | return midiBuffer[fromBuffer]; 52 | } 53 | 54 | 55 | void putNoteIn(unsigned char note){ 56 | if(note<6) hw.freezeAllKnobs(); 57 | if(notesInBuffer==BUFFER_SIZE-1) removeNote(midiBuffer[BUFFER_SIZE-1]); 58 | removeNote(note); // check if the note is already in the buffer if yes remove it 59 | if(notesInBufferZERO){ 61 | shiftBufferRight(); 62 | } 63 | midiBuffer[ZERO]=note; // put the last note to the first place 64 | notesInBuffer++; 65 | thereIsNoteToPlay=true; 66 | fromBuffer=ZERO; 67 | } 68 | 69 | 70 | if(thereIsNoteToPlay) { 71 | if(legato && note>=23 && note<66 && notesInBuffer>1) sound=note,sampleRateNow=(pgm_read_word_near(noteSampleRateTable+sound-23)),wave.setSampleRate(sampleRateNow); 72 | else playSound(midiBuffer[ZERO]); 73 | } 74 | // hw.freezAllKnobs(); 75 | } 76 | 77 | void clearBuffer(){ 78 | for(int i=ZERO;iZERO){ 83 | unsigned char takenOut; 84 | boolean takeOut=ZERO; 85 | 86 | for(int i=ZERO;i0){ 106 | if(midiBuffer[ZERO]!=sound) { 107 | if(legato && midiBuffer[ZERO]>=23 && midiBuffer[ZERO]<66) sound=midiBuffer[ZERO],sampleRateNow=(pgm_read_word_near(noteSampleRateTable+sound-23)),wave.setSampleRate(sampleRateNow); 108 | else playSound(midiBuffer[ZERO]),instantLoop=0; 109 | } //legatoPosition=wave.getCurPosition(), 110 | } 111 | else if(!sustain) stopEnvelope(),instantLoop=0; 112 | return midiBuffer[ZERO]; 113 | 114 | } 115 | 116 | 117 | 118 | 119 | } 120 | 121 | 122 | 123 | void initMidi(){ 124 | clearBuffer(); 125 | readMidiChannel(); 126 | Serial.begin(MIDI_BAUD); 127 | 128 | } 129 | #define SIDE_CHANNEL 1022 130 | #define SIDE_NOTE 1021 131 | #define SIDE_DECAY 1020 132 | 133 | unsigned char controler, CCvalue; 134 | void readMidiChannel(){ 135 | 136 | channelSide=EEPROM.read(SIDE_CHANNEL); 137 | 138 | sideNote=EEPROM.read(SIDE_NOTE); 139 | sideDecay=EEPROM.read(SIDE_DECAY); 140 | channel=EEPROM.read(MIDI_CHANNEL); 141 | if(channel>16) EEPROM.write(MIDI_CHANNEL,0), channel=0; 142 | 143 | showValue(channel+1); 144 | hw.displayChar('C',0); 145 | hw.displayChar('H',1); 146 | 147 | hw.update(); 148 | for(int i=0;i<6;i++){ 149 | if(hw.buttonState(bigButton[i])){ 150 | if(hw.buttonState(UP) && hw.buttonState(DOWN)) sideDecay=i, EEPROM.write(SIDE_DECAY,sideDecay), showValue(sideDecay), hw.displayChar('S',0), hw.displayChar('D',1); 151 | else if(hw.buttonState(UP)) channelSide=i+6*hw.buttonState(FN), EEPROM.write(SIDE_CHANNEL,channelSide), showValue(channelSide+1), hw.displayChar('S',0), hw.displayChar('C',1); 152 | else if(hw.buttonState(DOWN)) sideNote=i+60*hw.buttonState(FN), EEPROM.write(SIDE_NOTE,sideNote), showValue(sideNote), hw.displayChar('S',0), hw.displayChar('N',1); 153 | else channel=i+6*hw.buttonState(FN),EEPROM.write(MIDI_CHANNEL,channel); 154 | } 155 | } 156 | 157 | if(wave.isPlaying()){ 158 | while(!wave.isPaused()) hw.update(); 159 | } 160 | stopSound(); 161 | 162 | } 163 | 164 | long lastClockPosition, clockLength; 165 | //unsigned char pByte1,pByte2; 166 | //boolean pb; 167 | boolean side; 168 | int bytesAvailable; 169 | void readMidi(){ 170 | 171 | 172 | //channel=map(analogRead(4),0,1024,0,16); 173 | while(Serial.available() > 0){ 174 | bytesAvailable=Serial.available(); 175 | if (bytesAvailable <= 0) return; 176 | if(bytesAvailable>=64) Serial.flush(); // If the buffer is full -> Don't Panic! Call the Vogons to destroy it. 177 | else { 178 | 179 | // read the incoming byte: 180 | 181 | unsigned char incomingByte = Serial.read(); 182 | Serial.write(incomingByte); // thru 183 | 184 | switch (state){ 185 | case 0: 186 | if( handleRealTime(incomingByte)); 187 | 188 | else if(incomingByte < 128) { // if running status byte 189 | if(!ignore){ // 190 | if(cc) controler=incomingByte; 191 | // else if(pb) pByte1=incomingByte; 192 | else note=incomingByte; 193 | state=2; 194 | } 195 | } 196 | 197 | if (incomingByte== (144 | channel)){ // look for as status-byte, our channel, note on 198 | state=1; 199 | ignore=false; 200 | cc=false; 201 | comandOff=false; 202 | side=false; 203 | // pb=false; 204 | } 205 | 206 | else if (incomingByte== (0x80 | channel)){ // look for as status-byte, our channel, note off 207 | state=1; 208 | ignore=false; 209 | comandOff=true; 210 | cc=false; 211 | side=false; 212 | // pb=false; 213 | 214 | } 215 | else if (incomingByte== (0xB0 | channel)){ // look for as status-byte, our channel, controlchange 216 | state=1; 217 | ignore=false; 218 | cc=true; 219 | comandOff=false; 220 | side=false; 221 | // comandOff=true; 222 | 223 | } 224 | /* 225 | else if (incomingByte== (0xE0 | channel)){ //pitchBend 226 | state=1; 227 | ignore=false; 228 | cc=false; 229 | pb=true; 230 | } 231 | */ 232 | 233 | else if (incomingByte== (144 | channelSide)){ // look for as status-byte, our channel, note on 234 | state=1; 235 | ignore=false; 236 | cc=false; 237 | side=true; 238 | // pb=false; 239 | } 240 | 241 | else if(incomingByte>127){ 242 | ignore=true; 243 | } 244 | 245 | 246 | 247 | break; 248 | 249 | case 1: 250 | // get the note to play or stop 251 | if(incomingByte < 128) { 252 | if(cc) controler=incomingByte; 253 | // else if(pb) pByte1=incomingByte; 254 | else note=incomingByte; 255 | state=2; 256 | } 257 | else{ 258 | if(!handleRealTime(incomingByte)) state = 0; 259 | // reset state machine as this should be a note number 260 | } 261 | break; 262 | 263 | case 2: // get the velocity / cc value 264 | 265 | if(incomingByte < 128) { 266 | if(cc){ 267 | CCvalue=incomingByte; 268 | proceedCC(controler,CCvalue); 269 | } 270 | //else if(pb) pByte2=incomingByte, proceedPB(pByte1,pByte2); 271 | else if(side) proceedSideChain(note),side=false; 272 | 273 | else{ 274 | if(incomingByte!=0){ 275 | if(comandOff){ 276 | putNoteOut(note); 277 | comandOff=false; 278 | 279 | } 280 | else{ 281 | midiVelocity=incomingByte; 282 | 283 | putNoteIn(note); 284 | // hw.freezeAllKnobs(); 285 | 286 | // midiNoteOn=true; 287 | } 288 | } 289 | else{ 290 | putNoteOut(note); 291 | comandOff=false; 292 | 293 | // midiNoteOn=false; 294 | } 295 | } 296 | 297 | state = 0; 298 | 299 | } 300 | else if(!handleRealTime(incomingByte)) state = 0; 301 | 302 | // state=0; 303 | 304 | } 305 | // Serial.write(incomingByte); 306 | } 307 | } 308 | } 309 | 310 | void proceedSideChain(unsigned char _note){ 311 | if(_note==sideNote){ 312 | if(sideDecay==0) startEnvelope(midiVelocity,attackInterval); 313 | else startEnvelope(midiVelocity,sideDecay<<2); 314 | } 315 | } 316 | boolean handleRealTime(unsigned char _incomingByte){ 317 | if(_incomingByte==0xF8){ //clock 318 | clockCounter++; 319 | // sync shiftSpeed - unnecessary 320 | // clockLength=abs(wave.getCurPosition()-lastClockPosition); 321 | // sync shiftSpeed - unnecessary 322 | slave=true; 323 | return true; 324 | } 325 | else if(_incomingByte==0xFA){ //start 326 | clockCounter=0; 327 | slave=true; 328 | return true; 329 | 330 | } 331 | else if(_incomingByte==0xFC){ //stop 332 | clockCounter=0; 333 | slave=true; 334 | return true; 335 | } 336 | else return false; 337 | } 338 | 339 | #define SUSTAIN_PEDAL_BYTE 64 340 | #define PRESET_BY_CC_BYTE 0 341 | #define RANDOMIZE_BYTE 127 342 | 343 | #define CONTROL_CHANGE_BITS 7 344 | #define CONTROL_CHANGE_OFFSET 102 345 | #define CONTROL_CHANGE_OFFSET_2 110 346 | 347 | void proceedCC(unsigned char _number,unsigned char _value){ 348 | 349 | if(_number==1) setVar(activeSound,LOOP_LENGTH,scale(_value,CONTROL_CHANGE_BITS,variableDepth[LOOP_LENGTH])), hw.unfreezeAllKnobs(),renderTweaking(1),hw.freezeAllKnobs(); //modwheel 350 | if(_number==SUSTAIN_PEDAL_BYTE){ 351 | sustain=_value>>6; 352 | if(!sustain && notesInBuffer==0) stopEnvelope(),instantLoop=0; 353 | } 354 | 355 | if(_number==PRESET_BY_CC_BYTE) loadPreset(currentBank,myMap(_value,128,NUMBER_OF_PRESETS)); 356 | 357 | // else if(_number==RANDOMIZE_BYTE) randomize(activeSound); 358 | 359 | else if(_number>=CONTROL_CHANGE_OFFSET && _number 5 | boolean rec, recording; 6 | int blinkCounter; 7 | boolean blinkState; 8 | unsigned char recSound; 9 | boolean thru; 10 | unsigned char indexedHash=0; 11 | boolean indexed(unsigned char _sound){ 12 | return bitRead(indexedHash,_sound); 13 | } 14 | void indexed(unsigned char _sound,boolean _state){ 15 | bitWrite(indexedHash,_sound,_state); 16 | } 17 | long index[NUMBER_OF_SOUNDS]; 18 | void clearIndexes(){ 19 | indexedHash=0; 20 | } 21 | void initSdCardAndReport(){ 22 | if (!card.init()) error("card"); 23 | if (!vol.init(&card));// error("vol "); 24 | if (!root.openRoot(&vol));// error("root"); 25 | /* 26 | uint8_t bpc = vol.blocksPerCluster(); 27 | // PgmPrint("BlocksPerCluster: "); 28 | 29 | //Serial.println(bpc, DEC); 30 | 31 | uint8_t align = vol.dataStartBlock() & 0X3F; 32 | // PgmPrint("Data alignment: "); 33 | //Serial.println(align, DEC); 34 | 35 | // PgmPrint("sdCard size: "); 36 | //Serial.print(card.cardSize()/2000UL); 37 | 38 | 39 | if (align || bpc < 64) { 40 | // PgmPrintln("\nFor best results use a 2 GB or larger card."); 41 | //// PgmPrintln("Format the card with 64 blocksPerCluster and alignment = 0."); 42 | // PgmPrintln("If possible use SDFormater from www.sdcard.org/consumers/formatter/"); 43 | } 44 | if (!card.eraseSingleBlockEnable()) { 45 | // PgmPrintln("\nCard is not erase capable and can't be used for recording!"); 46 | } 47 | */ 48 | } 49 | 50 | uint8_t playBegin(char* name,unsigned char _sound) { 51 | 52 | if(indexed(_sound)){ 53 | if (!file.open(&root, index[_sound], O_READ)) { 54 | return false; 55 | } 56 | } 57 | else{ 58 | //name 59 | if (!file.open(&root,name, O_READ)) { 60 | return false; 61 | } 62 | else{ 63 | index[_sound]=root.curPosition()/32-1; 64 | indexed(_sound,true); 65 | } 66 | 67 | 68 | 69 | } 70 | 71 | 72 | /* 73 | if (!file.open(&root, name, O_READ)) { 74 | // index[_sound 75 | // if (!file.open(&root, index, O_READ)) 76 | // PgmPrint("Can't open: "); 77 | // Serial.println(name); 78 | return false; 79 | } 80 | */ 81 | 82 | if (!wave.play(&file)) { 83 | // PgmPrint("Can't play: "); 84 | // Serial.println(name); 85 | file.close(); 86 | return false; 87 | } 88 | return true; 89 | } 90 | 91 | 92 | 93 | 94 | void error(char* str) { 95 | // hw.initialize(); 96 | hw.displayText(str); 97 | while(1){ 98 | hw.updateDisplay(); 99 | } 100 | } 101 | 102 | 103 | 104 | // record a track 105 | unsigned char updt; 106 | 107 | void trackRecord(unsigned char _sound,unsigned char _preset) { 108 | stopSound(); 109 | // Serial.flush(); 110 | // Serial.end(); 111 | 112 | //name="30.WAV"; 113 | // noInterrupts(); 114 | 115 | name[0]=currentBank + 48; 116 | _preset=currentPreset*6+_sound; 117 | if(_preset<10) name[1]=_preset+48; 118 | else name[1]=_preset+55; 119 | 120 | 121 | if (file.open(&root,name, O_READ)) { 122 | file.close(); 123 | if (SdFile::remove(&root, name)) { 124 | // hw.displayText("redy"); 125 | } 126 | else return; 127 | 128 | // return; 129 | 130 | } 131 | if (!file.createContiguous(&root, name, MAX_FILE_SIZE)) { 132 | // hw.displayText("eror"); 133 | return; 134 | } 135 | wave.adcInit(RECORD_RATE, MIC_ANALOG_PIN, ADC_REFERENCE); 136 | hw.displayText("redy"); 137 | hw.setLed(bigButton[_sound],true); 138 | 139 | 140 | while(1){ 141 | updt++; 142 | if(updt>3) updt=0, hw.updateDisplay(); 143 | hw.updateButtons(); 144 | hw.updateDisplay(); 145 | 146 | // hw.updateMatrix(); //hack 147 | blinkLed(REC,FAST_INTERVAL); 148 | // for(int i=0;i0 || envelopePhase==2 || sustain){ 31 | 32 | if(!wave.isPaused()){ //isPlaying 33 | renderEnvelope(); 34 | renderLooping(); 35 | renderGranular(); 36 | 37 | } 38 | else { 39 | // setSetting(midiBuffer[ZERO]); 40 | setSetting(activeSound); 41 | if(repeat){ 42 | loadValuesFromMemmory(sound); 43 | } 44 | else stopSound(); 45 | } 46 | } 47 | 48 | if(notesInBuffer>0){ 49 | setSetting(activeSound); 50 | if(!wave.isPlaying() || wave.isPaused()){ 51 | if(repeat) playSound(midiBuffer[ZERO]); 52 | } 53 | } 54 | 55 | } 56 | 57 | int instantClockCounter; 58 | void renderLooping(){ 59 | long _pos=wave.getCurPosition(); 60 | if(instantLoop==2){ 61 | if(sync){ 62 | if((clockCounter % instantClockCounter)==0){ 63 | wave.pause(); 64 | wave.seek(instantStart); 65 | wave.resume(); 66 | lastPosition=instantStart; 67 | } 68 | } 69 | else{ 70 | if(shiftSpeed<0 && loopLength!=0){ 71 | if(_pos<=instantEnd){ 72 | wave.pause(); 73 | wave.seek(instantStart); 74 | wave.resume(); 75 | lastPosition=instantStart; 76 | } 77 | } 78 | else{ 79 | if(_pos>=instantEnd){ 80 | wave.pause(); 81 | wave.seek(instantStart); 82 | wave.resume(); 83 | lastPosition=instantStart; 84 | } 85 | } 86 | } 87 | } 88 | else{ 89 | 90 | 91 | if(shiftSpeed<0 && loopLength!=0){ 92 | if(sync){ 93 | if(endIndex!=1000){ 94 | if((clockCounter % endIndex)==0){ 95 | if(repeat) wave.pause(),loadValuesFromMemmory(sound); 96 | else stopSound(); 97 | } 98 | } 99 | } 100 | else{ 101 | if(_pos<= startPosition ){ 102 | if(repeat) wave.pause(),loadValuesFromMemmory(sound), wave.pause(), lastPosition=endPosition,wave.seek(lastPosition),wave.resume(); 103 | else stopSound(); 104 | } 105 | } 106 | /* 107 | if(_pos>= lastPosition ){ 108 | lastPosition+=shiftSpeed; 109 | 110 | wave.pause(); 111 | wave.seek(lastPosition); 112 | wave.resume(); 113 | } 114 | */ 115 | 116 | } 117 | else{ 118 | if(_pos<=startPosition) loadValuesFromMemmory(sound); 119 | if(sync){ 120 | if(endIndex!=1000){ 121 | if((clockCounter % endIndex)==0){ 122 | if(repeat) wave.pause(),loadValuesFromMemmory(sound); 123 | else stopSound(); 124 | } 125 | } 126 | } 127 | else{ 128 | if(_pos>=endPosition){ 129 | if(repeat) wave.pause(),loadValuesFromMemmory(sound); 130 | else stopSound(); 131 | } 132 | } 133 | } 134 | } 135 | // 136 | /* 137 | else{ 138 | 139 | if(wave.getCurPosition()>=endPosition){ 140 | if(repeat) wave.pause(),loadValuesFromMemmory(sound); 141 | else stopSound(); 142 | } 143 | 144 | if(wave.isPaused()){ 145 | if(repeat) loadValuesFromMemmory(sound); 146 | else stopSound(); 147 | } 148 | } 149 | */ 150 | // } 151 | } 152 | 153 | 154 | unsigned char velocity; 155 | int attackInt; 156 | void startEnvelope(unsigned char _velocity,int _attack){ 157 | envelopeTime=millis(); 158 | envelopeNow=37; 159 | envelopePhase=0; 160 | wave.setVolume(envelopeNow); 161 | velocity=31-(_velocity>>2); 162 | attackInt=_attack; 163 | } 164 | 165 | void stopEnvelope(){ 166 | envelopeTime=millis(); 167 | // envelopeNow=0; 168 | 169 | if(envelopePhase!=2) wave.setVolume(envelopeNow); 170 | envelopePhase=2; 171 | } 172 | 173 | void renderEnvelope(){ 174 | switch(envelopePhase){ 175 | case 0: 176 | if(attackInt==0) envelopePhase=1, envelopeNow=0,wave.setVolume(envelopeNow); 177 | else if(millis()-envelopeTime>=attackInt){ 178 | envelopeTime=millis(); 179 | if(attackInt<30) envelopeNow-=3; 180 | else envelopeNow--; 181 | if(envelopeNow<=velocity) envelopeNow=0, envelopePhase=1; 182 | wave.setVolume(envelopeNow); 183 | } 184 | 185 | break; 186 | case 1: 187 | envelopeNow=velocity; 188 | wave.setVolume(velocity); 189 | break; 190 | case 2: 191 | if(wave.isPlaying()){ 192 | if(releaseInterval==0) envelopePhase=3, envelopeNow=36,wave.setVolume(envelopeNow),stopSound(); 193 | if(millis()-envelopeTime>=releaseInterval){ 194 | envelopeTime=millis(); 195 | if(releaseInterval<30) envelopeNow+=3; 196 | else envelopeNow++; 197 | 198 | if(envelopeNow>=36) envelopePhase=3, stopSound(); 199 | wave.setVolume(envelopeNow); 200 | } 201 | } 202 | else{ 203 | envelopeNow=36; 204 | envelopePhase=3, stopSound(); 205 | wave.setVolume(envelopeNow); 206 | } 207 | 208 | break; 209 | case 3: 210 | stopSound(); 211 | break; 212 | } 213 | } 214 | long lastLL; 215 | 216 | static unsigned long x=132456789, y=362436069, z=521288629; 217 | 218 | unsigned long xorshift96() 219 | { //period 2^96-1 220 | // static unsigned long x=123456789, y=362436069, z=521288629; 221 | unsigned long t; 222 | 223 | x ^= x << 16; 224 | x ^= x >> 5; 225 | x ^= x << 1; 226 | 227 | t = x; 228 | x = y; 229 | y = z; 230 | z = t ^ x ^ y; 231 | 232 | return z; 233 | } 234 | 235 | int rand(int maxval) 236 | { 237 | return (int) (((xorshift96() & 0xFFFF) * maxval)>>16); 238 | } 239 | /* 240 | int rand( int minval, int maxval) 241 | { 242 | return (int) ((((xorshift96() & 0xFFFF) * (maxval-minval))>>16) + minval); 243 | } 244 | */ 245 | long granularTime; 246 | void renderGranular(){ 247 | 248 | 249 | 250 | if(loopLength!=0){ 251 | if(lastLL==0) lastPosition=wave.getCurPosition(); 252 | long pos=wave.getCurPosition(); 253 | 254 | if(sync){ 255 | 256 | if((clockCounter%loopLength)==0){ 257 | // sync shiftSpeed - unnecessary 258 | int _shiftSpeed=shiftSpeed; 259 | /* 260 | int _shiftSpeed=(int)getVar(sound,SHIFT_SPEED)-63; 261 | if(_shiftSpeed > 0) _shiftSpeed=pgm_read_word_near(usefulLengths+(abs(_shiftSpeed)>>3)) * clockLength; 262 | else _shiftSpeed=(int)-pgm_read_word_near(usefulLengths+(abs(_shiftSpeed)>>3)) * clockLength; 263 | // sync shiftSpeed - unnecessary 264 | */ 265 | /* 266 | if(shiftDir){ 267 | if(rand(2)==0) lastPosition+=_shiftSpeed; 268 | else lastPosition-=_shiftSpeed; 269 | } 270 | else 271 | */ 272 | lastPosition+=_shiftSpeed; //shift speed clock ??? 273 | 274 | wave.pause(); 275 | wave.seek(lastPosition); 276 | wave.resume(); 277 | } 278 | 279 | } 280 | 281 | else{ 282 | if(millis()-granularTime>=loopLength){ 283 | granularTime=millis(); 284 | 285 | //if(pos-lastPosition>=loopLength){ 286 | lastPosition+=shiftSpeed; 287 | if(lastPosition<0){ 288 | if(shiftSpeed<0) lastPosition=endPosition; 289 | else lastPosition=0; 290 | } 291 | wave.pause(); 292 | wave.seek(lastPosition); 293 | wave.resume(); 294 | } 295 | } 296 | 297 | 298 | } 299 | lastLL=loopLength; 300 | 301 | } 302 | 303 | 304 | -------------------------------------------------------------------------------- /UI.ino: -------------------------------------------------------------------------------- 1 | #define LOOP_LENGTH_SHIFT 4 //8 for possition based 2 | #define SHIFT_SPEED_SYNC_SHIFT 5 3 | #define SHIFT_SPEED_SHIFT 7 4 | 5 | boolean whileShow; 6 | long whileTime; 7 | 8 | #define WHILE_DURATION 1400 9 | #define NUMBER_OFFSET 48 10 | #define BIG_LETTER_OFFSET 65 11 | #define SMALL_LETTER_OFFSET 97 12 | #define NUMBER_OF_LETTERS 3 13 | 14 | #define PAGE_KNOB_LABEL_OFFSET 4 15 | unsigned char lastMoved; 16 | boolean combo; 17 | boolean shift; 18 | 19 | boolean tuned=true; 20 | 21 | #define TUNED_BIT 0 //1 22 | #define LEGATO_BIT 1 //0 23 | #define REPEAT_BIT 2 //1 24 | #define SYNC_BIT 3 //1 25 | #define SHIFT_DIR_BIT 4 //0 26 | 27 | //1101 28 | //TUNED, LEGATO, REPEAT, SYNC and RANDOM SHIFT 29 | long startGranule; 30 | 31 | 32 | 33 | #define DEFAULT_VELOCITY 127 34 | 35 | long longTime; 36 | boolean longPress; 37 | #define LONG_PERIOD 600 38 | #define MOVE_PERIOD 400 39 | 40 | //unsigned char updt; 41 | void UI(){ 42 | 43 | // if(!rec) 44 | // hw.updateDisplay(); 45 | if(rec){ 46 | hw.setColor(RED); 47 | hw.updateDisplay(); 48 | hw.updateButtons(); 49 | hw.displayText("slct"); 50 | renderRecordRoutine(); 51 | 52 | // updt++; 53 | // if(updt>1) updt=0, 54 | hw.updateDisplay(); 55 | // hw.updateKnobs(); 56 | 57 | // hw.updateDisplay(); 58 | // delay(1); 59 | } 60 | else{ 61 | 62 | hw.updateDisplay(); 63 | hw.updateButtons(); 64 | 65 | hw.updateKnobs(); 66 | renderCombo(); 67 | renderHold(); 68 | 69 | if(!combo){ 70 | if(hw.justReleased(PAGE)){ 71 | if(++page>=2) page=0; 72 | hw.freezeAllKnobs(); 73 | } 74 | 75 | if(hw.justPressed(REC)){ 76 | noSound(); 77 | hold=false; 78 | dimLeds(); 79 | clearBuffer(); 80 | rec=true; 81 | wave.adcInit(RECORD_RATE, MIC_ANALOG_PIN, ADC_REFERENCE); 82 | } 83 | 84 | renderBigButtons(); 85 | } 86 | hw.setLed(REC,false); 87 | hw.setColor(page+2); 88 | renderSmallButtons(); 89 | renderTweaking(page); 90 | renderKnobs(); 91 | renderDisplay(); 92 | } 93 | 94 | 95 | } 96 | void dimLeds(){ 97 | for(int i=0;i=23){ 104 | loadName(activeSound); 105 | startPlayback(activeSound); 106 | loadValuesFromMemmory(_sound); 107 | startEnvelope(midiVelocity,attackInterval); 108 | } 109 | else if(_sound<6){ 110 | 111 | activeSound=_sound; 112 | loadName(activeSound); 113 | startPlayback(activeSound); 114 | loadValuesFromMemmory(activeSound); 115 | startEnvelope(DEFAULT_VELOCITY,attackInterval); 116 | 117 | 118 | 119 | } 120 | 121 | } 122 | 123 | //long sizeOfFile; 124 | 125 | //samples per second*1000 - millisecond - how many samples? 126 | //x= sample Rate*number of samples / 1000 127 | long seekPosition; 128 | void setEnd(unsigned char _sound){ 129 | endIndex=getVar(_sound,END); 130 | if(sync) endIndex=pgm_read_word_near(usefulLengths+(endIndex>>6)+1); 131 | else{ 132 | //ending=true; 133 | if(endIndex<1022){ 134 | if(endIndex=23 && _sound <=73) startIndex=_sound-23, _sound=activeSound, startGranule=sizeOfFile/60; 151 | else if(_sound>=23 && _sound<66) notePitch=_sound-23,_sound=activeSound,startGranule=sizeOfFile/1024, startIndex=getVar(_sound,START); 152 | else _sound=activeSound,startGranule=sizeOfFile/1024, startIndex=getVar(_sound,START); 153 | startPosition=startIndex*startGranule; 154 | setSetting(_sound); 155 | attackInterval=getVar(_sound,ATTACK); 156 | releaseInterval=getVar(_sound,RELEASE); 157 | wave.pause(); 158 | 159 | if(notePitch!=255){ 160 | sampleRateNow=(pgm_read_word_near(noteSampleRateTable+notePitch)); 161 | } 162 | else{ 163 | sampleRateNow=valueToSampleRate(getVar(_sound,RATE)); 164 | } 165 | wave.setSampleRate(sampleRateNow);//+pitchBendNow); 166 | crush=getVar(_sound,CRUSH)<<1; 167 | wave.setCrush(crush); 168 | if(sync) loopLength=pgm_read_word_near(usefulLengths+(getVar(_sound,LOOP_LENGTH)>>3)); 169 | else loopLength=getVar(_sound,LOOP_LENGTH)<>3)); 251 | else loopLength=getVar(_sound,LOOP_LENGTH)<=1000) hw.lightNumber(1,0),hw.lightNumber(0,1); 287 | 288 | } 289 | void renderCombo(){ 290 | 291 | for(int i=0;i2) instantLoop=0; 323 | if(instantLoop==1){ 324 | instantStart=wave.getCurPosition(); 325 | if(sync) instantClockCounter=clockCounter; 326 | } 327 | if(instantLoop==2){ 328 | if(sync) instantClockCounter=clockCounter-instantClockCounter, instantClockCounter=snapToUseful(instantClockCounter); 329 | else instantEnd=wave.getCurPosition(); 330 | wave.pause(); 331 | wave.seek(instantStart); 332 | wave.resume(); 333 | lastPosition=instantStart; 334 | } 335 | } 336 | if(hw.justPressed(bigButton[5])) combo=true, demo(); 337 | 338 | } 339 | 340 | 341 | if(combo){ 342 | //turn off combo when all buttons are released 343 | unsigned char _count=0; 344 | for(int i=0;i= ((difference/2)+pgm_read_word_near(usefulLengths+smallerThan-1))) _clock=smallerThan; 361 | else _clock=smallerThan-1; 362 | _number=pgm_read_word_near(usefulLengths+_clock); 363 | return _number; 364 | } 365 | void renderSmallButtons(){ 366 | 367 | if(!combo){ 368 | 369 | if(hw.justPressed(UP)){ 370 | stopSound(); 371 | listNameUp(); 372 | setVar(activeSound,SAMPLE_NAME_1,name[0]); 373 | setVar(activeSound,SAMPLE_NAME_2,name[1]); 374 | sound=activeSound; 375 | if(notesInBuffer>0) playSound(sound); 376 | else showSampleName(),whileShow=true,whileTime=millis(); 377 | longTime=millis(); 378 | longPress=false; 379 | } 380 | 381 | if(hw.justPressed(DOWN)){ 382 | stopSound(); 383 | listNameDown(); 384 | setVar(activeSound,SAMPLE_NAME_1,name[0]); 385 | setVar(activeSound,SAMPLE_NAME_2,name[1]); 386 | sound=activeSound; 387 | if(notesInBuffer>0) playSound(sound); 388 | else showSampleName(),whileShow=true,whileTime=millis(); 389 | longTime=millis(); 390 | longPress=false; 391 | } 392 | 393 | if(hw.buttonState(DOWN) || hw.buttonState(UP)){ 394 | if(!longPress){ 395 | if((millis()-longTime) > LONG_PERIOD) longPress=true, longTime=millis(); 396 | } 397 | else{ 398 | if((millis()-longTime) > MOVE_PERIOD){ 399 | longTime=millis(); 400 | if(hw.buttonState(DOWN)){ 401 | downWithFirstLetter(); 402 | setVar(activeSound,SAMPLE_NAME_1,name[0]); 403 | hw.displayChar(name[0],2); 404 | whileShow=true,whileTime=millis(); 405 | 406 | 407 | } 408 | else if(hw.buttonState(UP)){ 409 | upWithFirstLetter(); 410 | setVar(activeSound,SAMPLE_NAME_1,name[0]); 411 | hw.displayChar(name[0],2); 412 | whileShow=true,whileTime=millis(); 413 | 414 | 415 | } 416 | } 417 | } 418 | } 419 | if(hw.justReleased(UP) || hw.justReleased(DOWN)){ 420 | if(longPress){ 421 | sound=activeSound; 422 | indexed(activeSound,false); 423 | if(notesInBuffer>0) playSound(sound); 424 | else showSampleName(),whileShow=true,whileTime=millis(); 425 | } 426 | } 427 | } 428 | 429 | } 430 | 431 | unsigned char interfaceSound; 432 | void renderBigButtons(){ 433 | 434 | for(int i=0;i0) hw.setLed(bigButton[i],true); 444 | else hw.setLed(bigButton[i],false); 445 | } 446 | } 447 | 448 | void renderRecordRoutine(){ 449 | if(recSound==0){ 450 | if(hw.justPressed(REC) || hw.justPressed(PAGE)) rec=false,restoreAnalogRead(),combo=true; 451 | if(hw.justPressed(HOLD)) thru=!thru,wave.setAudioThru(thru); 452 | hw.setLed(HOLD,thru); 453 | for(int i=0;i=((i+1)*31)) hw.setDot(i,true); 465 | else hw.setDot(i,false); 466 | } 467 | wave.adcClearRange(); 468 | } 469 | void renderHold(){ 470 | if(!shift){ 471 | if(hw.justPressed(HOLD)){ 472 | if(hold){ 473 | hold=false; 474 | unsigned char keepPlaying=255; 475 | for(int i=0;i0) _sound=activeSound; 493 | //else 494 | _sound=interfaceSound; 495 | 496 | for(int i=0;i7){ 515 | if((was>>2)!=(_value>>2)) { 516 | lastMoved=i; 517 | whileShow=true; 518 | whileTime=millis(); 519 | if(_variable==START) loadValuesFromMemmory(sound); //snap to start 520 | } 521 | 522 | } 523 | else if((was>>1)!=(_value>>1)) { 524 | lastMoved=i; 525 | whileShow=true; 526 | whileTime=millis(); 527 | } 528 | 529 | /* 530 | if(hw.knobMoved(i) || was!=_value) { 531 | lastMoved=i; 532 | whileShow=true; 533 | whileTime=millis(); 534 | } 535 | */ 536 | // if(was!=_value) 537 | 538 | boolean showSlash=false; 539 | if(lastMoved==i){ 540 | if(_variable==RATE){ 541 | if(tuned){ 542 | _value=pitch-36; 543 | // _value=myMap(_value,1024,43); 544 | // _value-=36; 545 | } 546 | else _value=pitch-360;//_value-=860; 547 | 548 | } 549 | else if(_variable==LOOP_LENGTH && sync){ 550 | _value=pgm_read_word_near(usefulLengths+(_value>>3)); 551 | if(_value<24 && _value>0) _value= 24/_value,showSlash=true; 552 | else _value/=24; 553 | } 554 | else if(_variable==SHIFT_SPEED){ 555 | _value-=128; 556 | } 557 | else if(_variable==END){ 558 | if(sync){ 559 | _value=pgm_read_word_near(usefulLengths+(_value>>6)+1); 560 | if(_value<24 && _value>0) _value= 24/_value,showSlash=true; 561 | else _value/=24; 562 | } 563 | else _value=endIndex; 564 | } 565 | hw.displayChar(pgm_read_word_near(labels + i + page*PAGE_KNOB_LABEL_OFFSET),0); 566 | showValue(_value); 567 | if(showSlash) hw.lightNumber(SLASH,1); 568 | 569 | } 570 | } 571 | 572 | } 573 | // } 574 | /* 575 | else{ 576 | lastMoved=5; 577 | 578 | } 579 | */ 580 | 581 | if(notesInBuffer==0) for(int i=0;iWHILE_DURATION) whileShow=false,showSampleName(),noDots(),lastMoved=5; 608 | } 609 | else if(!wave.isPlaying() && !rec) { 610 | for(int i=0;i<4;i++) hw.lightNumber(LINES,i); 611 | noDots(); 612 | } 613 | else{ 614 | showSampleName(); 615 | noDots(); 616 | } 617 | //showValue(bytesAvailable); 618 | } 619 | 620 | 621 | 622 | void showForWhile(char *show){ 623 | whileShow=true; 624 | whileTime=millis(); 625 | hw.displayText(show); 626 | } 627 | 628 | 629 | void blinkLed(unsigned char _LED,int interval){ 630 | if(++blinkCounter >= interval) blinkCounter=0, blinkState=!blinkState; 631 | hw.setLed(_LED,blinkState); 632 | // 633 | } 634 | 635 | 636 | void randomize(unsigned char _sound){ 637 | for(int i=0;i<10;i++) setVar(_sound,i,rand(maxVal(i))); 638 | setVar(_sound,CRUSH,rand(20)); 639 | } 640 | 641 | unsigned char copyMemory[NUMBER_OF_BYTES]; 642 | void copy(unsigned char _sound){ 643 | showForWhile("copy"); 644 | for(int i=0;i=58 && name[1]<65) name[1]=65; 6 | else if(name[1]>=91){ 7 | name[1]=48; 8 | upWithFirstLetter(); 9 | 10 | } 11 | while(!file.open(&root, name, O_READ)){ 12 | // hw.updateM 13 | hw.updateDisplay(); 14 | hw.displayText("SRCH"); 15 | name[1]+=searchIndex; 16 | searchIndex++; 17 | if(name[1]>=58 && name[1]<65) name[1]=65,searchIndex=1; 18 | else if(name[1]>=91){ 19 | name[1]=48; 20 | upWithFirstLetter(); 21 | searchIndex=1; 22 | } 23 | } 24 | file.close(); 25 | indexed(activeSound,false); 26 | if(!playBegin(name,activeSound)) listNameUp(); 27 | stopSound(); 28 | searchIndex=1; 29 | 30 | } 31 | void listNameDown(){ 32 | 33 | name[1]--; 34 | if(name[1]<48){ 35 | name[1]=90; 36 | downWithFirstLetter(); 37 | 38 | } 39 | else if(name[1]<65 && name[1]>58) name[1]=58; 40 | 41 | while(!file.open(&root, name, O_READ)){ 42 | hw.updateDisplay(); 43 | hw.displayText("SRCH"); 44 | name[1]-=searchIndex; 45 | searchIndex++; 46 | if(name[1]<48){ 47 | name[1]=90; 48 | downWithFirstLetter(); 49 | searchIndex=1; 50 | } 51 | else if(name[1]<65 && name[1]>58) name[1]=58,searchIndex=1; 52 | } 53 | file.close(); 54 | indexed(activeSound,false); 55 | 56 | if(!playBegin(name,activeSound)) listNameDown(); 57 | 58 | stopSound(); 59 | searchIndex=1; 60 | } 61 | 62 | void upWithFirstLetter(){ 63 | name[0]++; 64 | if(name[0]>=58 && name[0]<65) name[0]=65; 65 | else if(name[0]>=91) name[0]=48,name[1]=48; 66 | } 67 | void downWithFirstLetter(){ 68 | name[0]--; 69 | if(name[0]<65 && name[0]>58) name[0]=58; 70 | if(name[0]<48) name[0]=90,name[1]=90; 71 | 72 | } 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /microGranny2.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * _ __ ___ / ___|___ \ / _ \ 4 | * | '_ ` _ \| | _ __) || | | | 5 | * | | | | | | |_| |/ __/ | |_| | 6 | * |_| |_| |_|\____|_____(_)___/ 7 | * 8 | * 9 | * microGranny 2.0 10 | * by Vaclav Pelousek http://www.pelousek.net/ 11 | * for Bastl Instruments http://www.bastl-instruments.com/ 12 | * 13 | * based on WaveRP library Adafruit Wave Shield - Copyright (C) 2009 by William Greiman 14 | * -library heavily hacked - BIG THX https://code.google.com/p/waverp/ 15 | * 16 | * needs SD Fat library too https://code.google.com/p/sdfatlib/ 17 | * 18 | * 19 | * 20 | * -thanks for understanding basics thru Mozzi library http://sensorium.github.io/Mozzi/ 21 | * -written in Arduino + using SDFat library 22 | * 23 | * 24 | * beta testing and help: Ondrej Merta, Ryba, HRTL 25 | * 26 | * monophonic granular sampler 27 | * 28 | * Features: 29 | * -6 big play buttons, 6 function buttons, 4 knobs, rgb led, 4 digit 7 segment display, bunch of leds 30 | * -6 samples with full adjustment in 1 preset 31 | * -12 presets 32 | * -wav sample playback from microSD card 33 | * -record wav via line or onboard microphone 34 | * -hold button 35 | * -sample rate (tuned or free run) 36 | * -crush 37 | * -start, end possition 38 | * -looping mode 39 | * -instant loop 40 | * -granular loop lenght 41 | * -shift speed (possitive or negative) 42 | * -enevlope (attack, release) 43 | * -MIDI Input + MIDI thru 44 | * -responsive to note, cc and clock (synchronize loop and grains) 45 | * -randomizer 46 | * -copy paste 47 | * -input & output volume knob 48 | * -power switch 49 | * -wooden enclosure 50 | * 51 | * 52 | * 53 | */ 54 | #include 55 | #include 56 | #include 57 | #include 58 | //#include 59 | #include 60 | //#include 61 | #include 62 | #include 63 | 64 | 65 | 66 | ///#include 67 | 68 | 69 | #define RECORD_RATE 22050 // try pot !! 70 | 71 | #define MAX_FILE_SIZE 104857600UL // 100 MB 72 | //#define MAX_FILE_SIZE 1048576000UL // 1 GB 73 | #define MIC_ANALOG_PIN 0 // Analog pin connected to mic preamp 74 | // Voltage Reference Selections for ADC 75 | //#define ADC_REFERENCE ADC_REF_AREF // use voltage on AREF pin 76 | #define ADC_REFERENCE ADC_REF_AVCC // use 5V VCC 77 | 78 | //#define DISPLAY_RECORD_LEVEL 1 79 | 80 | #define MIDI_BAUD 31250 81 | //------------------------------------------------------------------------------ 82 | // global variables 83 | Sd2Card card; // SD/SDHC card with support for version 2.00 features 84 | SdVolume vol; // FAT16 or FAT32 volume 85 | SdFile root; // volume's root directory 86 | SdFile file; // current file 87 | WaveRP wave; // wave file recorder/player 88 | mg2HW hw; 89 | //------------------------------------------------------------------------------ 90 | 91 | 92 | 93 | long seekTo; 94 | unsigned char crush; 95 | unsigned char volume; 96 | long lastPosition; 97 | unsigned char currentPreset=0; 98 | unsigned char currentBank=0; 99 | #define E_BANK 1001 100 | #define E_PRESET 1002 101 | 102 | void setup(void) { 103 | 104 | hw.initialize(); 105 | initSdCardAndReport(); 106 | //Serial.begin(9600); 107 | 108 | 109 | if(!EEPROM.read(1000)) playBegin("ZZ.WAV",7); 110 | else EEPROM.write(1000,0),currentPreset=EEPROM.read(E_PRESET),currentBank=EEPROM.read(E_BANK); 111 | initMidi(); 112 | //Serial.begin(MIDI_BAUD); 113 | 114 | initMem(); 115 | // clearMemmory(); 116 | restoreAnalogRead(); 117 | // hw.freezeAllKnobs(); 118 | } 119 | 120 | void restoreAnalogRead() 121 | { 122 | ADCSRA=135; // default ARDUINO B10000111 123 | } 124 | 125 | 126 | void software_Reset() // Restarts program from beginning but does not reset the peripherals and registers 127 | { 128 | asm volatile (" jmp 0"); 129 | } 130 | 131 | void loop() { 132 | readMidi();//,hw.displayText("midi"); 133 | // readMidi(); 134 | UI(); 135 | // readMidi(); 136 | // readMidi(); 137 | updateSound(); 138 | // readMidi(); 139 | // readMidi(); 140 | } 141 | 142 | 143 | 144 | --------------------------------------------------------------------------------