' Picaxe Beatbox ' (C) 3/07 A. Stein, MedCosm, LLC ' ' A picaxe 08M records a beat which is tapped in and loops playback ' until you want to tap in a new one... ' ' uses 2 piezos, 1 for input (with cross diode protection to avoid spiking the picaxe, and ' any high impedence resistor to bleed the natural capacitance of the piezo), ' and 1 for output ' also uses LED for signalling, not really necessary, but a nice touch ' ' It took me a while to figure out I needed a bleeding resistor across the piezo, othewise ' some erratic behaviour resulted. ' ' Need a leading edge detector because the piezo has an exponential decay after tapping it ' ' v1 - basic record functionality working ' v2 - compression (bit packing) to allow more samples in memory ' also finds last beat to allow variable length loops ' doesn't start recording until the first beat is played ' v3 - some code optimization to fit a bit more into the algorithms, better edge detection ' v4 - 2 input pads and major/minor beat noises ' v5 - memory optimizations and powerdown mode ' v6 - sensor debounce via intelligent playback instead of leading edge detection, ' switch to LDR sensor from piezo ' v7 - bitpacking simplified (shorter code) due to great help from picaxe forum. Thanks Hippy! ' powerdown mode added, and turn-on at night eliminated ' ' LED on = record mode ' LED off = playback mode ' ' Start tapping a beat once the device is in record mode Recording doesn't start until the first ' beat is tapped. The last beat played becomes the first beat of the loop. ' Press the pad during playback and a moment later the device will enter record mode again. ' ' Tap the pad sharply, don't rest your finger on it or you may get extra beats. 'pinouts symbol sensor1=2 'pad1 sensor symbol sensor2=1 'pad2 sensor symbol piezoOut=4 'piezo output symbol led=0 'use 1 for LED indicator 'vars symbol tmpB1=b0 'tmp byte variables symbol tmpB2=b1 symbol tmpB3=b2 symbol tmpB4=b3 symbol tmpW1=w2 symbol tmpB5=b4 symbol tmpB6=b5 symbol ptr1=b6 'memory ptr1 symbol smpMultiplier=b7 symbol lastSmp=b8 'last sample found symbol smpMask=b9 'first sample found symbol smpNum=b10 'sample number symbol smpVal=b11 'sample value symbol smpByte=b12 'sample byte within RAM symbol smpPack=b13 'sample pack within byte 'constants symbol smpDlyRec=20 'delay between samples (msec) during record symbol smpDlyPly=20 'delay between samples (msec) during playback symbol soundDur=2 'sound duration, approx smpDly/10 symbol sound1Tone=60 'sound to play for a pad1 beat symbol sound2Tone=110 'sound to play for a pad2 beat symbol powerDownRecCnt=1500 'number of zero recording samples until jump to powerdown mode symbol powerDownPlyCnt=5000 'number of playback samples until jump to powerdown mode symbol memPtr=$50 'ptr to start of 48 bytes of free RAM at $50-$7F symbol maxPts=184 'max num of pts to store in RAM (48*4=192 is absolute max!) symbol sensor1Thresh=40 'thresholds for pad sensors, account for differences in spare components used symbol sensor2Thresh=65 symbol minSmpLoop=5 'any sample loop shorter than this causes powerdown init: start: high led 'led on while recording pause 500 'pause for a sec before record mode... tmpW1=0 smpNum=0 'start recording at sample 0 'record beats on piezo and store in RAM record: do readadc sensor1, tmpB1 'read piezo sensor readadc sensor2, tmpB2 'read piezo sensor smpVal=0 if tmpB1powerDownRecCnt then goto enterPowerDown 'if no loop recording started eventually, powerdown endif pause smpDlyRec 'pause until next sample loop while smpNum0 then 'set last sample to last beat-1 lastSmp=smpNum-1 endif next smpNum ' tmpW1=0 'set timeout watchdog back to zero 'play beat via piezo and keep looping 'if piezo is pressed then restart in record mode playSoundLoop: tmpB1=255 'variable that signals loop play interruption via piezo press tmpB3=255 low LED for smpNum=0 to lastSmp 'recording loop gosub getSample if smpVal=0 then 'if recorded sample is nothing pause smpDlyPly 'then play a pause tmpB2=0 'note that pause occurred elseif smpVal=tmpB2 then 'if current sample=previous sample pause smpDlyPly 'then pause instead of playing sound else if smpVal=1 then 'sample is nonzero sound piezoOut, (sound1Tone, soundDur) elseif smpVal=2 then 'sample is nonzero sound piezoOut, (sound2Tone, soundDur) endif tmpB2=smpVal 'save sample value for next go around endif if tmpB1>sensor1Thresh and tmpB3>sensor2Thresh then 'if piezo hasn't been pressed, then readadc sensor1, tmpB1 'read sensor1 readadc sensor2, tmpB3 'read sensor2 endif tmpW1=tmpW1+1 if tmpW1>powerDownPlyCnt then goto enterPowerDown 'if no loop recording started eventually, powerdown next smpNum high LED 'flash LED to let user know we're active if tmpB1>sensor1Thresh and tmpB3>sensor2Thresh then goto playSoundLoop 'if user hasn't pressed piezo, loop goto start 'else go back to record mode 'calculate sample byte and pack within byte and get sample byte from RAM 'smpByte, smpPack, smpVal getSampleByte: smpByte=smpNum/4 'find proper byte smpPack=smpNum%4 'and sample within byte lookup smpPack, (1,4,16,64), smpMultiplier 'get multiplier: 00000001, 00000100, 00010000, or 01000000 ptr1=memPtr + smpByte peek ptr1, smpVal 'get sample[tmpB1] from RAM return 'get sample from RAM, packed as 4 samples to a byte 'smpVal, smpNum getSample: gosub getSampleByte smpMask=smpMultiplier*3 ' generate mask: 00000011, 00001100, 00110000, or 11000000 smpVal=smpVal & smpMask 'and mask out proper bits from byte smpVal=smpVal/smpMultiplier endGetSample: return 'low power mode to save batteries enterPowerDown: low led powerDown: readadc sensor1, tmpB1 'read sensor1 readadc sensor2, tmpB2 'read sensor2 if tmpB1sensor2Thresh then goto start 'press pad 1 to turn on, avoid turn on at night ' if tmpB1>sensor1Thresh and tmpB2