Most Guitar-to-MIDI converters are a grave disappointment. Recently, I’ve been playing with the idea of adding electronic scanning to one of my guitars and using this to output MIDI – it works but has several disadvantages, not the least being that it involves irreversible surgery to a guitar. My prototype is a £35 (GBP) second-hand acoustic Fender Squier. It’s ‘just-good-enough’ as a test bed, but I don’t lose any sleep despite hurting it – a lot.
Work is still on-going, but encouraging, and I’m busy now scaling everything down in size so that most of it can be put inside the guitar body, rather than bolted onto the top of the soundboard. In parallel with this work, I’ve been playing recently with a small Guitar-to-MIDI project featured in EPE Magazine October 2009. This little unit is impressive and beats hands-down the relatively expensive SONUS/MODUS stuff around.
The project has been quite popular, and I’ve decided to incorporate some of the techniques into my own unit. I haven’t decided on a final format to present my work in yet, but will use this post, and maybe others, to fully document the work.
The first thing I did to the EPE unit was add diagnostics and look at the code in action on the oscilloscope. Others who have tackled/are tackling the project might benefit from these so I’m publishing these here.
First of all here’s a trace capture showing the initial string pluck and the subsequent processing. Refer to the source-code I’ve supplied for both the ‘PEAK’ and ‘TIMING’ routines which will show you where I’ve output the blue diagnostic trace transitions.
Secondly, here’s a set of traces with the ‘TIMING’ routine annotated in more detail.
And now for the relevant code. Note my #ifdef CODESHOW conditional compilation to provide the blue trace transitions in the oscilloscope dumps above. First the PEAKS routine:
;--- WAVEFORM PEAK LEVEL DETECTION FOR 12MS --- PEAKS #ifdef CODESHOW BCF PORTB,0 #endif CLRF PEAKH ; PEAKH := 0; MOVLW 255 MOVWF PEAKL ; PEAKL := 255 ; !!! JWB use TMR0 instead of loop counter bcf INTCON,2 movlw 255-110 ; [for ~14ms to accomodate drop 'D'] : 14ms = 28,000 CKP at FOSC 8Mhz/4. Prescaled at 256 is count of 109.375. movwf TMR0 CL1 CALL ADC MOVF ADRESH,W ; W := PEAKH - ADC SUBWF PEAKH,W BTFSS STATUS,C CALL UPDATE_PEAKH MOVF PEAKL,W ; W := PEAKL - ADC SUBWF ADRESH,W BTFSS STATUS,C CALL UPDATE_PEAKL ; test TMR0 hasn't timed out BTFSS INTCON,2 GOTO CL1 #ifdef CODESHOW BSF PORTB,0 #endif RETURN UPDATE_PEAKH MOVF ADRESH,W ; PEAKH := ADC MOVWF PEAKH RETURN UPDATE_PEAKL MOVF ADRESH,W ; PEAKL := ADC MOVWF PEAKL RETURN
And now the ‘TIMING‘ routine.
TIMING CLRF TMR1L CLRF TMR1H #ifdef CODESHOW ; debug BCF PORTB, 0 #endif T1 BTFSC TMR1H,5 GOTO TERROR BCF MARKER,3 CALL ADC MOVF TRIGL,W SUBWF ADRESH,W BTFSC STATUS,C ;IS ADRESH - TRIGL +VE IE CARRY SET? GOTO T1 ;NO, SO RETEST UNTIL IT IS #ifdef CODESHOW ; debug BSF PORTB,0 #endif T2 BTFSC TMR1H,5 GOTO TERROR CALL ADC MOVF ADRESH,W SUBWF TRIGH,W BTFSC STATUS,C ;IS ADRESH - TRIGH +VE IE CARRY SET? GOTO T2 ;NO, SO RETEST UNTIL IT IS CLRF TMR1L CLRF TMR1H NOP #ifdef CODESHOW ; debug BCF PORTB, 0 #endif T3 BTFSC TMR1H,5 GOTO TERROR CALL ADC MOVF TRIGL,W SUBWF ADRESH,W BTFSC STATUS,C ;IS ADRESH - TRIGL +VE IE CARRY SET? GOTO T3 ;YES, SO RETEST UNTIL IT IS #ifdef CODESHOW ; debug BSF PORTB, 0 #endif T4 BTFSC TMR1H,5 GOTO TERROR CALL ADC MOVF ADRESH,W SUBWF TRIGH,W BTFSC STATUS,C ;IS ADRESH - TRIGH +VE IE CARRY SET? GOTO T4 ;NO, SO RETEST UNTIL IT IS BCF T1CON,0 ;STOP THE TIMER TO RETRIEVE THE DATA #ifdef CODESHOW ; debug BCF PORTB,0 #endif MOVF TMR1L,W MOVWF LOBYTE MOVF TMR1H,W MOVWF HIBYTE BSF T1CON,0 ;RESTART THE TIMER #ifdef CODESHOW ; debug BSF PORTB,0 #endif RETURN TERROR BSF MARKER,3 RETURN
Note that I’ve made one or two changes to the original code. I’ve detailed these in the source-header, which is given below:
; GUITAR TO MIDI CONVERTER ; ; This version V2.00 modified by JWB 03 Sep 2010 ; 1. Now using 8Mhz Osc. ; 2. Added facilities to debug on serial port ; and PORTB,0 output pin ; 3. Annotated lookup table ; ; JWB 4 sep ; 1. Now using TMR0 instead of loop counter in PEAKS routine ; To allow easier definition of 'window' ; Also frees up 2 RAM slots ; ERRORLEVEL -302 ; JWB 7th Aug 2010 remove message about using proper bank
My amended source-code is appended in a zip file here: http://joebrown.org.uk/images/GuitarToMIDI/PICGUITARTOMIDI._5sep2010.zip