Welcome, Guest
Username: Password: Remember me

TOPIC: Arbitrary Instrumental Pitch Shift Code

Arbitrary Instrumental Pitch Shift Code 4 years 3 months ago #158

  • CB
  • CB's Avatar
  • OFFLINE
  • New Member
  • Posts: 1
  • Thank you received: 2
  • Karma: 1
Hi all, and thanks JR for putting the pedalShield project together.

I've put together some code for a harmoniser pedal, intended for use with a trombone, but any wind instrument and some others should work ok.

The code takes an input signal and pitch shifts it by up to 5 predefined intervals simultaneously, with the harmonies triggered by buttons/foot pedals wired to pins 14,15,16,18 and 19.

I am putting this up here both as a resource for anyone looking to do something similar, and for any suggested improvements the community may have, particularly those which might reduce noise!

The pitch shift method used is the instrumental pitch shift described in section 1.3 here: http://dsp-book.narod.ru/Pitch_shifting.pdf

//1024 values - Cosine lookup, could have more
int DISTLOOKUP[]={
  0, 0, 2, 5, 9, 15, 22, 30, 39, 49, 61, 74, 88, 104, 120, 138, 
  157, 178, 199, 222, 246, 271, 298, 325, 354, 384, 416, 448, 482, 517, 553, 591, 
  629, 669, 710, 752, 796, 840, 886, 933, 982, 1031, 1082, 1133, 1186, 1241, 1296, 1353, 
  1410, 1469, 1530, 1591, 1653, 1717, 1782, 1848, 1915, 1983, 2053, 2123, 2195, 2268, 2342, 2417, 
  2494, 2571, 2650, 2730, 2811, 2893, 2976, 3060, 3146, 3232, 3320, 3408, 3498, 3589, 3681, 3774, 
  3869, 3964, 4060, 4158, 4256, 4356, 4457, 4559, 4661, 4765, 4870, 4976, 5083, 5191, 5301, 5411, 
  5522, 5634, 5747, 5862, 5977, 6093, 6210, 6329, 6448, 6568, 6690, 6812, 6935, 7059, 7184, 7310, 
  7437, 7566, 7695, 7824, 7955, 8087, 8220, 8353, 8488, 8623, 8760, 8897, 9035, 9174, 9314, 9455, 
  9597, 9740, 9883, 10027, 10173, 10319, 10466, 10613, 10762, 10911, 11061, 11212, 11364, 11517, 11670, 11825, 
  11980, 12136, 12292, 12449, 12608, 12766, 12926, 13087, 13248, 13409, 13572, 13735, 13899, 14064, 14230, 14396, 
  14563, 14730, 14898, 15067, 15237, 15407, 15578, 15749, 15921, 16094, 16268, 16442, 16616, 16791, 16967, 17144, 
  17321, 17498, 17677, 17855, 18035, 18215, 18395, 18576, 18757, 18939, 19122, 19305, 19489, 19673, 19857, 20042, 
  20228, 20414, 20600, 20787, 20974, 21162, 21351, 21539, 21728, 21918, 22108, 22298, 22489, 22680, 22871, 23063, 
  23255, 23448, 23641, 23834, 24028, 24222, 24416, 24611, 24806, 25001, 25196, 25392, 25588, 25784, 25981, 26178, 
  26375, 26572, 26770, 26967, 27165, 27364, 27562, 27761, 27959, 28158, 28358, 28557, 28756, 28956, 29156, 29356, 
  29556, 29756, 29956, 30156, 30357, 30558, 30758, 30959, 31160, 31361, 31561, 31762, 31963, 32164, 32365, 32566, 
  32768, 32969, 33170, 33371, 33572, 33773, 33974, 34175, 34375, 34576, 34777, 34978, 35178, 35379, 35579, 35779, 
  35979, 36179, 36379, 36579, 36779, 36978, 37177, 37377, 37576, 37774, 37973, 38171, 38370, 38568, 38765, 38963, 
  39160, 39357, 39554, 39751, 39947, 40143, 40339, 40534, 40729, 40924, 41119, 41313, 41507, 41701, 41894, 42087, 
  42280, 42472, 42664, 42855, 43046, 43237, 43427, 43617, 43807, 43996, 44184, 44373, 44561, 44748, 44935, 45121, 
  45307, 45493, 45678, 45862, 46046, 46230, 46413, 46596, 46778, 46959, 47140, 47320, 47500, 47680, 47858, 48037, 
  48214, 48391, 48568, 48744, 48919, 49093, 49267, 49441, 49614, 49786, 49957, 50128, 50298, 50468, 50637, 50805, 
  50972, 51139, 51305, 51471, 51636, 51800, 51963, 52126, 52287, 52449, 52609, 52769, 52927, 53086, 53243, 53399, 
  53555, 53710, 53865, 54018, 54171, 54323, 54474, 54624, 54773, 54922, 55069, 55216, 55362, 55508, 55652, 55795, 
  55938, 56080, 56221, 56361, 56500, 56638, 56775, 56912, 57047, 57182, 57315, 57448, 57580, 57711, 57841, 57969, 
  58098, 58225, 58351, 58476, 58600, 58723, 58845, 58967, 59087, 59206, 59325, 59442, 59558, 59673, 59788, 59901, 
  60013, 60124, 60234, 60344, 60452, 60559, 60665, 60770, 60874, 60976, 61078, 61179, 61279, 61377, 61475, 61571, 
  61666, 61761, 61854, 61946, 62037, 62127, 62215, 62303, 62389, 62475, 62559, 62642, 62724, 62805, 62885, 62964, 
  63041, 63118, 63193, 63267, 63340, 63412, 63482, 63552, 63620, 63687, 63753, 63818, 63882, 63944, 64005, 64066, 
  64125, 64182, 64239, 64294, 64349, 64402, 64453, 64504, 64553, 64602, 64649, 64695, 64739, 64783, 64825, 64866, 
  64906, 64944, 64982, 65018, 65053, 65087, 65119, 65151, 65181, 65210, 65237, 65264, 65289, 65313, 65336, 65357, 
  65378, 65397, 65415, 65431, 65447, 65461, 65474, 65486, 65496, 65505, 65513, 65520, 65526, 65530, 65533, 65535, 
  65536, 65535, 65533, 65530, 65526, 65520, 65513, 65505, 65496, 65486, 65474, 65461, 65447, 65431, 65415, 65397, 
  65378, 65357, 65336, 65313, 65289, 65264, 65237, 65210, 65181, 65151, 65119, 65087, 65053, 65018, 64982, 64944, 
  64906, 64866, 64825, 64783, 64739, 64695, 64649, 64602, 64553, 64504, 64453, 64402, 64349, 64294, 64239, 64182, 
  64125, 64066, 64005, 63944, 63882, 63818, 63753, 63687, 63620, 63552, 63482, 63412, 63340, 63267, 63193, 63118, 
  63041, 62964, 62885, 62805, 62724, 62642, 62559, 62475, 62389, 62303, 62215, 62127, 62037, 61946, 61854, 61761, 
  61666, 61571, 61475, 61377, 61279, 61179, 61078, 60976, 60874, 60770, 60665, 60559, 60452, 60344, 60234, 60124, 
  60013, 59901, 59788, 59673, 59558, 59442, 59325, 59206, 59087, 58967, 58845, 58723, 58600, 58476, 58351, 58225, 
  58098, 57969, 57841, 57711, 57580, 57448, 57315, 57182, 57047, 56912, 56775, 56638, 56500, 56361, 56221, 56080, 
  55938, 55795, 55652, 55508, 55362, 55216, 55069, 54922, 54773, 54624, 54474, 54323, 54171, 54018, 53865, 53710, 
  53555, 53399, 53243, 53086, 52927, 52769, 52609, 52449, 52287, 52126, 51963, 51800, 51636, 51471, 51305, 51139, 
  50972, 50805, 50637, 50468, 50298, 50128, 49957, 49786, 49614, 49441, 49267, 49093, 48919, 48744, 48568, 48391, 
  48214, 48037, 47858, 47680, 47500, 47320, 47140, 46959, 46778, 46596, 46413, 46230, 46046, 45862, 45678, 45493, 
  45307, 45121, 44935, 44748, 44561, 44373, 44184, 43996, 43807, 43617, 43427, 43237, 43046, 42855, 42664, 42472, 
  42280, 42087, 41894, 41701, 41507, 41313, 41119, 40924, 40729, 40534, 40339, 40143, 39947, 39751, 39554, 39357, 
  39160, 38963, 38765, 38568, 38370, 38171, 37973, 37774, 37576, 37377, 37177, 36978, 36779, 36579, 36379, 36179, 
  35979, 35779, 35579, 35379, 35178, 34977, 34777, 34576, 34375, 34174, 33974, 33773, 33572, 33371, 33170, 32969, 
  32768, 32566, 32365, 32164, 31963, 31762, 31561, 31360, 31160, 30959, 30758, 30557, 30357, 30156, 29956, 29756, 
  29556, 29356, 29156, 28956, 28756, 28557, 28358, 28158, 27959, 27761, 27562, 27364, 27165, 26967, 26770, 26572, 
  26375, 26178, 25981, 25784, 25588, 25392, 25196, 25001, 24806, 24611, 24416, 24222, 24028, 23834, 23641, 23448, 
  23255, 23063, 22871, 22680, 22489, 22298, 22108, 21918, 21728, 21539, 21351, 21162, 20974, 20787, 20600, 20414, 
  20228, 20042, 19857, 19673, 19489, 19305, 19122, 18939, 18757, 18576, 18395, 18214, 18035, 17855, 17677, 17498, 
  17321, 17144, 16967, 16791, 16616, 16442, 16268, 16094, 15921, 15749, 15578, 15407, 15237, 15067, 14898, 14730, 
  14563, 14396, 14230, 14064, 13899, 13735, 13572, 13409, 13248, 13087, 12926, 12766, 12608, 12449, 12292, 12136, 
  11980, 11825, 11670, 11517, 11364, 11212, 11061, 10911, 10762, 10613, 10466, 10319, 10173, 10027, 9883, 9740, 
  9597, 9455, 9314, 9174, 9035, 8897, 8760, 8623, 8488, 8353, 8220, 8087, 7955, 7824, 7694, 7566, 
  7437, 7310, 7184, 7059, 6935, 6812, 6690, 6568, 6448, 6329, 6210, 6093, 5977, 5862, 5747, 5634, 
  5522, 5411, 5301, 5191, 5083, 4976, 4870, 4765, 4661, 4559, 4457, 4356, 4256, 4158, 4060, 3964, 
  3869, 3774, 3681, 3589, 3498, 3408, 3320, 3232, 3146, 3060, 2976, 2893, 2811, 2730, 2650, 2571, 
  2494, 2417, 2342, 2268, 2195, 2123, 2053, 1983, 1915, 1848, 1782, 1717, 1653, 1591, 1530, 1469, 
  1410, 1353, 1296, 1241, 1186, 1133, 1082, 1031, 982, 933, 886, 840, 796, 752, 710, 669, 
  629, 591, 553, 517, 482, 448, 416, 384, 354, 325, 298, 271, 246, 222, 199, 178, 
  157, 138, 120, 104, 88, 74, 61, 49, 39, 30, 22, 15, 9, 5, 2, 0
};
 
int in_ADC0, in_ADC1, avg;  //variables for 2 ADCs values (ADC0, ADC1) and average of both
 
int POT0, POT1, POT2, out_DAC0, out_DAC1 ; //variables for 3 pots (ADC8, ADC9, ADC10) & OUTPUTs
int PITCHARRAY[]={2048,2048,2048,2048,2048};
int PITCHINDEX[]={0,0,0,0,0};
 
#define LED 3
#define FOOTSWITCH 7 
#define TOGGLE 2   
const int BUTTONS[]={14,15,16,18,19};
const int PITCHES[]={77936,82570,98193,32768,131072};  //2^16 * frequency delta factor (minor 3rd, major 3rd, 5th, down octave, up octave)
 
unsigned int BUTTONSTATES[]={0,0,0,0,0};
#define BUTTONFADECOUNTERMAX 4096
unsigned int BUTTONFADECOUNTER[]={0,0,0,0,0};
boolean FASTBUTTONSTATES[]={0,0,0,0,0};
 
boolean footSwitch=true;
boolean toggle=true;
 
#define BUFFERSIZE 4096   //4096 is a suitable minimum
#define HALFBUFFERSIZE 2048
int BUFFER[BUFFERSIZE]; //a circular buffer, could save memory by using short ints
unsigned int pitchWriteIndex=0;
 
#define MAXDELAYBUFFERSIZE 32768
short DELAYBUFFER[MAXDELAYBUFFERSIZE];
int delayWriteIndex=0;
 
#define bias 2035

//---------------------------------------------------------------------------------------------------------------------------------------------------------------
void setup()
{
  Serial.begin(9600);
  Serial.println("PedalShield HW Test");
 
  for(int i=0;i<MAXDELAYBUFFERSIZE;i++){
    DELAYBUFFER[i]=bias; //initialise buffers(?)
  }
  for(int i=0;i<BUFFERSIZE;i++){
    BUFFER[i]=bias; //initialise buffers(?)
  }
 
  //turn on the timer clock in the power management controller
  pmc_set_writeprotect(false);
  pmc_enable_periph_clk(ID_TC4);
 
  //we want wavesel 01 with RC 
  TC_Configure(TC1, 1, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK2);
  TC_SetRC(TC1, 1, 238); // 109 sets ~96 Khz interrupt rate. for ~44.1kHz use 238, for 72.5kHz use 145, for 48kHz use 219
  TC_Start(TC1, 1);
 
  // enable timer interrupts on the timer
  TC1->TC_CHANNEL[1].TC_IER = TC_IER_CPCS;
  TC1->TC_CHANNEL[1].TC_IDR = ~TC_IER_CPCS;
 
  //Enable the interrupt in the nested vector interrupt controller
  //TC4_IRQn where 4 is the timer number * timer channels (3) + the channel
  //number (=(1*3)+1) for timer1 channel1
  NVIC_EnableIRQ(TC4_IRQn);
 
  //ADC Configuration
  ADC->ADC_MR |= 0x80;   // DAC in free running mode.
  ADC->ADC_CR = 2;         // Starts ADC conversion.
  ADC->ADC_CHER = 0x1CC0;  // Enable ADC channels 0, 1, 8, 9, 10. 
 
  // enable ADC interrupts on the timer
  ADC->ADC_IER = 0x00C0;
  ADC->ADC_IDR = ~0x00C0;
 
  //Enable the interrupt in the nested vector interrupt controller 
  NVIC_EnableIRQ(ADC_IRQn); 
 
  //DAC Configuration
  analogWrite(DAC0,0);  // Enables DAC0
  analogWrite(DAC1,0);  // Enables DAC1
 
  //pedalSHIELD pin configuration
  pinMode(LED, OUTPUT);  
  pinMode(FOOTSWITCH, INPUT_PULLUP);      
  pinMode(TOGGLE, INPUT_PULLUP);  
 
  for(int i=0;i<5;i++){
    pinMode(BUTTONS[i],INPUT_PULLUP);
  }
}
 
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
void loop()
{  
//  Serial.println(bias);
//  delay(20);
 
  //Read the ADCs
  while((ADC->ADC_ISR & 0x1C00) != 0x1C00)
    ;  // wait for ADC 8, 9, 10 conversion complete.    
  POT0 = ADC->ADC_CDR[10];                 // read data from ADC8    
  POT1 = ADC->ADC_CDR[11];                 // read data from ADC9   
  POT2 = ADC->ADC_CDR[12];                 // read data from ADC10 
 
  for(int i=(POT2<<3)+1;i<MAXDELAYBUFFERSIZE;i++){
    DELAYBUFFER[i]=bias;                                 //zero delay buffer elements
  }
 
  if (footSwitch!=digitalRead(FOOTSWITCH)){
    footSwitch=!footSwitch;
    analogWrite(LED, footSwitch);   //dim led
    //analogWrite(LED, abs(in_ADC0-2048)>>3); 
    //digitalWrite(LED, footSwitch);
  }
 
  if(footSwitch){
    buttonUpdate();
  }else{
    if((millis()%5000)<10){   //flash every 5 seconds when powered but not "active"
      analogWrite(LED,255);    
    }else{
      analogWrite(LED,0);
    }
  }
 
  if (toggle!=digitalRead(TOGGLE)){
    toggle=!toggle;
  }
 
  //bias=(bias*biasEMA+in_ADC0*(65536-biasEMA))>>16;
 
}
 
//--------------------------------------------------------------------------------------------------------------------------------------------------------------- 
 
 
void TC4_Handler() //Interrupt at chosen rate
{ 
  TC_GetStatus(TC1, 1); //Clear status to fire again the interrupt.
 
  if(footSwitch){
 
    if(toggle){
      BUFFER[pitchWriteIndex]=volumeAdd4096(volumeAdd4096(in_ADC0,4095-in_ADC1),volumeMult4096(out_DAC0,POT1<<1));   //add input to buffer; plus variable (POT1) feedback if toggle switch is on
    }else{
      BUFFER[pitchWriteIndex]=volumeAdd4096(in_ADC0,4095-in_ADC1);   //add input to buffer
    }
 
    for(int i=0;i<5;i++){
 
      if((BUTTONSTATES[i]==3)&&(FASTBUTTONSTATES[i]==false)){
        FASTBUTTONSTATES[i]=true;
        PITCHINDEX[i]=pitchWriteIndex<<16;
        BUTTONFADECOUNTER[i]++;
      }
 
      if(BUTTONFADECOUNTER[i]>0){   
        int dist=DISTLOOKUP[((pitchWriteIndex-(PITCHINDEX[i]>>16)+BUFFERSIZE)%BUFFERSIZE)>>2];  //rescales to 1024 - could calculate more values in setup
        PITCHARRAY[i]=((getBufInterp(BUFFER, BUFFERSIZE, PITCHINDEX[i])*dist)>>16) + ((getBufInterp(BUFFER, BUFFERSIZE, PITCHINDEX[i]+(HALFBUFFERSIZE<<16))*(65536-dist))>>16);
 
        PITCHARRAY[i]=volumeMult4096(PITCHARRAY[i],BUTTONFADECOUNTER[i]<<4); //fade in/out volume
 
        PITCHINDEX[i]+=PITCHES[i];  
        if(PITCHINDEX[i]>(BUFFERSIZE<<16)){PITCHINDEX[i]-=BUFFERSIZE<<16;} //limit within array - could maybe fine tune buffersize here
 
        if(FASTBUTTONSTATES[i]==true){
          if(BUTTONFADECOUNTER[i]<BUTTONFADECOUNTERMAX){
            BUTTONFADECOUNTER[i]++;  //increment counter while counter<max time
          }
        }
      }
 
      if(BUTTONSTATES[i]<2){
        if(BUTTONFADECOUNTER[i]>0){
          BUTTONFADECOUNTER[i]--;
        }
        FASTBUTTONSTATES[i]=false;
      }
 
    }
 
    out_DAC0=(PITCHARRAY[0]*90 + PITCHARRAY[1]*85 + PITCHARRAY[2]*71 + PITCHARRAY[3]*213 + PITCHARRAY[4]*53) >>9; //mixer (bit crappy)
 
    if(toggle){
      DELAYBUFFER[delayWriteIndex]=short(out_DAC0);
      delayWriteIndex++;           
      delayWriteIndex%=(POT2<<3)+1;                                                  //causes clicking?
      out_DAC0=int(DELAYBUFFER[delayWriteIndex]);                                  //play what's in the buffer instead
    }
 
    out_DAC0=volumeMult4096(out_DAC0,POT0<<8);  //gain and clipping, can easily make parametric
    out_DAC1=out_DAC0;
  }
 
  pitchWriteIndex++;
  pitchWriteIndex%=BUFFERSIZE;
 
  //Write the DACs
  dacc_set_channel_selection(DACC_INTERFACE, 0);       //select DAC channel 0
  dacc_write_conversion_data(DACC_INTERFACE, out_DAC0);//write on DAC
  dacc_set_channel_selection(DACC_INTERFACE, 1);       //select DAC channel 1  //do I need to write both?
  dacc_write_conversion_data(DACC_INTERFACE, out_DAC1);//write on DAC
}
 
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
void ADC_Handler()
{
  int adcisr = ADC->ADC_ISR;
 
  if((adcisr & 0x0080) == 0x0080) // wait for ADC 0, 1 conversion complete.
    in_ADC0 = ADC->ADC_CDR[7];               // read data from ADC0
 
  if((adcisr & 0x0040) == 0x0040) // wait for ADC 0, 1 conversion complete.
    in_ADC1 = ADC->ADC_CDR[6];               // read data from ADC1  
 
  //avg=(in_ADC0+in_ADC1)>>1;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
int getBufInterp(int* ARRAYINPUT, int BUFFSIZE, int INDEX){
  //INDEX should be float bufferPosition * 2^16
  //linear interpolation - allows you to ask for an array entry between indexes e.g. getValInterp(listOfValues, 1024, 34.7*(2^16)); will return a proportional mix of the values at indexes 34 and 35
  //will loop back at the end of the array, e.g. it's possible to request indexes longer than the input
  int LOWER  = INDEX>>16;
  if((INDEX%65536)==0){
    return (ARRAYINPUT[LOWER%BUFFSIZE]);
  }else{
    return linInterp(ARRAYINPUT[LOWER%BUFFSIZE], ARRAYINPUT[LOWER%BUFFSIZE+1], INDEX%65536);
  }
}
 
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
int linInterp(int IN1, int IN2, int WEIGHT){
  return (IN1*(65536-WEIGHT) + IN2*WEIGHT)>>16;
}
 
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
void buttonUpdate(){
  for(int i=0;i<5;i++){
    boolean buttonState=digitalRead(BUTTONS[i]);
    if(BUTTONSTATES[i]==3){
      BUTTONSTATES[i]=2;
    }
    if((buttonState==LOW)&&(BUTTONSTATES[i]==0)){
      BUTTONSTATES[i]=3;
    }
    if(BUTTONSTATES[i]==1){
      BUTTONSTATES[i]=0;
    }
    if((buttonState==HIGH)&&(BUTTONSTATES[i]==2)){
      BUTTONSTATES[i]=1;
    }
  }
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
 
void dumpToSerial(int* INPUTARRAY, int DUMPSIZE){
  Serial.println("DUMP START--------------------------------------------------------------");
  for(int i=0; i<DUMPSIZE; i++){
    Serial.print(i);
    Serial.print("\t");
    Serial.println(INPUTARRAY[i]);
  }
  Serial.println("FINISHED DUMPING--------------------------------------------------------");
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
 
int volumeMult4096(int INPUTSAMPLE,int VOLFACTOR){
  //simple linear volume change (clips over 1) 
  //INPUTSAMPLE is between 0 and 4096
  //VOLFACTOR is equal to 2^16F, e.g. a doubling of volume would be 2^16*2 = 131072, assumes bias of 2048
  return constrain((((INPUTSAMPLE-bias)*VOLFACTOR)>>16)+bias,0,4095);
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
 
int volumeMix4096(int INPUTSAMPLE1,int INPUTSAMPLE2,int MIX){
  //simple volume mixer for two samples, contrains to 4095, variable mix of two samples, MIX should be expressed x*(2^16) where x is between 0 and 1.
  return constrain((INPUTSAMPLE1*(65536-MIX)+INPUTSAMPLE2*MIX)>>16,0,4095);
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
 
int volumeAdd4096(int INPUTSAMPLE1,int INPUTSAMPLE2){   //beware unsigned
  //simple volume adder for two samples, contrains to 4095, assumes bias of 2048
  return constrain(INPUTSAMPLE1+INPUTSAMPLE2-bias,0,4095);
}
 

The code is in a "just barely finished" state, and I'd describe myself as a beginner when it comes to programming for MCUs, so any suggestions for improvements/alterations based on standard practice would be very welcome. I also made a snazzy enclosure - pictures attached.
Attachments:
The administrator has disabled public write access.
The following user(s) said Thank You: JR, KennethDStewart

Arbitrary Instrumental Pitch Shift Code 4 years 3 months ago #160

  • JR
  • JR's Avatar
  • OFFLINE
  • Senior Member
  • Posts: 77
  • Thank you received: 31
  • Karma: 6
Thanks for your contribution and for the pitch shifting information! ;)
I like your steam punk enclosure, I will post it on the ElectroSmash facebook...
keep it simple
Last Edit: 4 years 3 months ago by JR.
The administrator has disabled public write access.
Time to create page: 0.196 seconds
Powered by Kunena Forum
Joomla SEF URLs by Artio

Our Instagram

Follow us

You can also follow us on:

facebook   google   instagram

pinterest   youtube   twitter