' ******************************************************* ' * design code for midi controlled robots and automats * ' * * ' * an automated sousaphone * ' ******************************************************* ' compile with PBCC ' valve combinations and optimum resonance. ' for our sousaphone robot [18.08.2003]: TYPE SoType DWORD ' used as an array (0 to so.hightes) - static in g_lib.dll ventiel AS BYTE ' gives the valve combination required for the requested note bit 0 = 1/2 tone, 1=1 tone , 2=2 tones minwind AS BYTE ' gives the minimum required wind pressure from the blower maxwind AS BYTE ' gives the maximum allowable wind pressure for the blower mindrive AS BYTE ' gives the minimum required amplitude for the coil driver maxdrive AS BYTE ' gives the maximum allowable driver amplitude DC AS BYTE ' if False, AC mode should be enabled for this note, if true, we use DC mode to drive head. ' mapped op note 50 (bit 2) in So.ctrl(6) latchadr AS BYTE ' reflects hardware connections - users should never ever change the data here. latchdta AS BYTE ' a single bit is set for the mosfets to be driven. Do not play around with this. v(7) AS SINGLE ' gives the resonant frequency for every valve combination. Internal use. END TYPE %So_Empirical = 2 %So_Acoustic = 0 %So_DC = 1 %False = 0 %True = 1 DECLARE FUNCTION So_Lookup (BYVAL param AS DWORD) AS LONG ' 24.08.2003 - zat in g_indep.dll FUNCTION PBMAIN () STATIC f AS LONG LOCAL i AS LONG LOCAL v$ LOCAL gronddo AS SINGLE DIM s(0 TO 127) AS GLOBAL SoType gronddo = 440.00 * (2!^(3!/12!))/64! f= FREEFILE OPEN "So_valves.txt" FOR OUTPUT AS #f i = So_Lookup(%So_Acoustic) PRINT #f, "So valve combination lookup tables" PRINT #f, "Values based on acoustic theory:" FOR i = 0 TO 47 PRINT #f, "note=";i, "f="; STR$(Gronddo * (2 ^ (i/12!))), 'BIN$(s(i).ventiel and &B00000111), "v-min:"; STR$( s(i).mindrive),"v-max:";STR$ (s(i).maxdrive) SELECT CASE (s(i).ventiel AND &B00000111) CASE 0 v$ = "0 0 0" CASE 1 v$ = "0 0 1" CASE 2 v$ = "0 1 0" CASE 3 v$ = "0 1 1" CASE 4 v$ = "1 0 0" CASE 5 v$ = "1 0 1" CASE 6 v$ = "1 1 0" CASE 7 v$ = "1 1 1" END SELECT ' measured with velo = 127 ' if we set ctrl 7 at 127, these are the ranges for velo s(12).mindrive = 23 s(12).maxdrive = 42 s(13).mindrive = 16 s(13).maxdrive = 42 s(14).mindrive = 20 s(14).maxdrive = 44 s(15).mindrive = 16 s(15).maxdrive = 48 s(16).mindrive = 20 s(16).maxdrive = 42 s(17).mindrive = 20 s(17).maxdrive = 42 s(18).mindrive = 15 s(18).maxdrive = 42 s(19).mindrive = 16 s(19).maxdrive = 42 s(20).mindrive = 16 s(20).maxdrive = 44 s(21).mindrive = 17 s(21).maxdrive = 46 s(22).mindrive = 20 s(22).maxdrive = 47 s(23).mindrive = 20 s(23).maxdrive = 50 s(24).mindrive = 20 s(24).maxdrive = 52 s(25).mindrive = 25 s(25).maxdrive = 63 s(26).mindrive = 30 s(26).maxdrive = 58 s(27).mindrive = 26 s(27).maxdrive = 80 s(28).mindrive = 30 s(28).maxdrive = 84 s(29).mindrive = 32 s(29).maxdrive = 86 s(30).mindrive = 32 s(30).maxdrive = 86 s(31).mindrive = 65 s(31).maxdrive = 86 s(32).mindrive = 60 s(32).maxdrive = 100 s(33).mindrive = 60 s(33).maxdrive = 102 s(34).mindrive = 64 s(34).maxdrive = 105 s(35).mindrive = 64 s(35).maxdrive = 105 s(36).mindrive = 60 s(36).maxdrive = 101 s(37).mindrive = 65 s(37).maxdrive = 88 s(38).mindrive = 28 s(38).maxdrive = 65 s(39).mindrive = 28 s(39).maxdrive = 66 s(40).mindrive = 26 s(40).maxdrive = 60 s(41).mindrive = 22 s(41).maxdrive = 54 s(42).mindrive = 28 s(42).maxdrive = 78 s(43).mindrive = 26 s(43).maxdrive = 75 s(44).mindrive = 43 s(44).maxdrive = 64 s(45).mindrive = 54 s(45).maxdrive = 74 s(46).mindrive = 62 s(46).maxdrive = 80 s(47).mindrive = 50 s(47).maxdrive = 83 PRINT #f, "valves: "; v$, "v-min:"; STR$( s(i).mindrive),"v-max:";STR$ (s(i).maxdrive) NEXT i PRINT #f, " " PRINT #f, "Empirical values for robot:" i = So_Lookup(%So_Empirical) FOR i = 12 TO 47 PRINT #f, "note=";i, "f="; STR$(Gronddo * (2 ^ (i/12!))), SELECT CASE (s(i).ventiel AND &B00000111) CASE 0 v$ = "0 0 0" CASE 1 v$ = "0 0 1" CASE 2 v$ = "0 1 0" CASE 3 v$ = "0 1 1" CASE 4 v$ = "1 0 0" CASE 5 v$ = "1 0 1" CASE 6 v$ = "1 1 0" CASE 7 v$ = "1 1 1" END SELECT PRINT #f, "valves: "; v$, "v-min:"; STR$( s(i).mindrive),"v-max:";STR$ (s(i).maxdrive) NEXT i CLOSE #f END FUNCTION ' removed from g_indep.dll: FUNCTION So_Lookup (BYVAL param AS DWORD) EXPORT AS LONG ' param: bit 0: '%So_Acoustic returns valve combination frequencies based on acoustics. ' %So_Empirical (= 2) returns empirical values for the robot ' bit 1: ' %So_DC if set, DC mode will be used for the pedal notes. ' 17.07.2003 - gwr ' rev. 23.08.2003 ' called by So_Play on init. ' calculates the valve position look-up table for ' now used to generate the lookups for the PIC microcontroller on the hub board: 18F2525 [07.2007] LOCAL v1 AS INTEGER, v2 AS INTEGER, v3 AS INTEGER LOCAL fb AS SINGLE LOCAL gronddo AS SINGLE LOCAL tun AS INTEGER ' basis stemming instrument als midi noot (22 = Bes, pedaal) LOCAL i AS DWORD LOCAL j AS DWORD gronddo = 440.00 * (2!^(3!/12!))/64! tun = 22 ' Sib ' berekening ventielen ' ventieldispositie: v1 = -1 ' in halve toon stappen - het v1 ventiel is het middelste !!! v2 = -2 ' rechterventiel v3 = -4 ' linkerventiel (normaal is dit -3, maar op veel sousafoons zoals deze is het -4) fb = Gronddo * (2 ^ (tun/12!)) 'N2F(22) ' grondtoon van het instrument zonder ingedrukte ventielen. ' boventoonreeksen: DIM n(16) AS LOCAL SINGLE ' zonder ventielen: FOR i = 1 TO 16 n(i) = (12! * (LOG(fb * i) - LOG(Gronddo)) / (LOG(2))) IF ROUND(n(i),0) <= UBOUND(s) THEN ' watch array boundaries... S(ROUND(n(i),0)).ventiel = 0 s(ROUND(n(i),0)).v(0) = n(i) END IF NEXT i ' met 1/2 toons ventiel: fb = Gronddo * (2.0 ^((tun+v1)/12!)) FOR i = 1 TO 16 n(i) = (12! * (LOG(fb * i) - LOG(Gronddo)) / (LOG(2))) IF ROUND(n(i),0) <= UBOUND(s) THEN S(ROUND(n(i),0)).ventiel = 1 '001 s(ROUND(n(i),0)).v(1) = n(i) END IF NEXT i ' met 1 toons ventiel: fb = Gronddo * (2.0 ^((tun+v2)/12!)) FOR i = 1 TO 16 n(i) = (12! * (LOG(fb * i) - LOG(Gronddo)) / (LOG(2))) IF ROUND(n(i),0) <= UBOUND(s) THEN S(ROUND(n(i),0)).ventiel = 2 ' 010 s(ROUND(n(i),0)).v(2) = n(i) END IF NEXT i ' met 1/2 + 1 toons ventiel: fb = Gronddo * (2.0 ^((tun+v1+v2)/12!)) FOR i = 1 TO 16 n(i) = (12! * (LOG(fb * i) - LOG(Gronddo)) / (LOG(2))) IF ROUND(n(i),0) <= UBOUND(s) THEN S(ROUND(n(i),0)).ventiel = 3 ' 011 s(ROUND(n(i),0)).v(3) = n(i) END IF NEXT i 'met derde ventiel: fb = Gronddo * (2.0 ^((tun+v3)/12!)) FOR i = 1 TO 16 n(i) = (12! * (LOG(fb * i) - LOG(Gronddo)) / (LOG(2))) IF ROUND(n(i),0) <= UBOUND(s) THEN S(ROUND(n(i),0)).ventiel = 4 ' 100 s(ROUND(n(i),0)).v(4) = n(i) END IF NEXT i ' met 1/2 + 2 toons ventiel: fb = Gronddo * (2.0 ^((tun+v1+v3)/12!)) FOR i = 1 TO 16 n(i) = (12! * (LOG(fb * i) - LOG(Gronddo)) / (LOG(2))) IF ROUND(n(i),0) <= UBOUND(s) THEN S(ROUND(n(i),0)).ventiel = 5 ' 101 s(ROUND(n(i),0)).v(5) = n(i) END IF NEXT i ' met 1 + 2 toons ventiel: fb = Gronddo * (2.0 ^((tun+v2+v3)/12!)) FOR i = 1 TO 16 n(i) = (12! * (LOG(fb * i) - LOG(Gronddo)) / (LOG(2))) IF ROUND(n(i),0) <= UBOUND(s) THEN S(ROUND(n(i),0)).ventiel = 6 ' 110 s(ROUND(n(i),0)).v(6) = n(i) END IF NEXT i ' met 1/2 + 1 + 2 toons ventiel: fb = Gronddo * (2.0 ^((tun+v1+v2+v3)/12!)) FOR i = 1 TO 16 n(i) = (12! * (LOG(fb * i) - LOG(Gronddo)) / (LOG(2))) IF ROUND(n(i),0) <= UBOUND(s) THEN S(ROUND(n(i),0)).ventiel = 7 ' 111 s(ROUND(n(i),0)).v(7) = n(i) END IF NEXT i ' we hebben nu de juiste resonantiefrekwenties in .v(n) voor elke mogelijke ventielkombinatie. ' nu moeten we de lookup berekenen voor de optimaalste ventielkombinatie voor elke gewenste midi noot. LOCAL sollf AS SINGLE LOCAL dif AS SINGLE LOCAL mindif AS SINGLE LOCAL vopt AS LONG LOCAL cnt AS LONG FOR i = 0 TO UBOUND(s) mindif = 50000 vopt = -1 sollf = Gronddo * (2.0^(i/12!)) FOR j = 0 TO 7 dif = ABS(sollf - S(i).v(j)) IF dif < mindif THEN mindif = dif vopt = j s(i).ventiel = vopt END IF NEXT j cnt = 0 FOR j = 0 TO 7 IF S(i).v(j) > 0 THEN INCR cnt END IF NEXT j IF ISFALSE cnt THEN ' unplayable note: we use the valve position for the one octave higher note. IF i+ 12 <= UBOUND(s) THEN S(i).ventiel = S(i+ 12).ventiel END IF END IF NEXT i ' nu moeten we de optimaalste ventielposities hebben in s().ventiel ' fill in values for other parameters: FOR i = 0 TO UBOUND(s) s(i).minwind = 10 '%False s(i).maxwind = 127 - i ' s(i).mindrive = &B00000101 ' 5 ' s(i).maxdrive = &B01111111 '127 - limited for safety. IF i < 22 THEN IF (param AND %So_DC) = %So_DC THEN s(i).dc = %True ' DC mode - this still causes glitches... ELSE s(i).dc = %False ' test, just to see whether now we get rid of glitches... END IF ELSE s(i).dc = %False ' AC mode END IF IF i < 12 THEN s(i).dc = %False ' AC mode for all external inputs. NEXT i ' drive limits for good sound: ' s(8).maxdrive = 96 ' to be checked with external drive inputs ' IF (param AND %So_DC) = %So_DC THEN ' ' DC drive amplitudes ' s(12).maxdrive = 57 ' s(13).maxdrive = 52 ' s(14).maxdrive = 52 ' s(15).maxdrive = 52 ' ' s(16).maxdrive = 64 ' s(17).maxdrive = 64 ' s(18).maxdrive = 96 ' s(19).maxdrive = 64 ' s(20).maxdrive = 96 ' s(21).maxdrive = 96 ' ELSE ' ' ac drive amplitudes ' s(12).maxdrive = 90 ' s(13).maxdrive = 96 ' s(14).maxdrive = 64 ' s(15).maxdrive = 48 ' ' s(16).maxdrive = 48 ' s(17).maxdrive = 64 ' s(18).maxdrive = 64 ' s(19).maxdrive = 64 ' s(20).maxdrive = 96 ' s(21).maxdrive = 64 ' END IF ' s(22).maxdrive = 92 ' s(23).maxdrive = 64 ' ' s(24).maxdrive = 64 ' s(25).maxdrive = 64 ' s(26).maxdrive = 64 ' s(27).maxdrive = 64 ' ' s(28).maxdrive = 64 ' s(29).maxdrive = 64 ' s(30).maxdrive = 64 ' s(31).maxdrive = 64 ' ' s(32).maxdrive = 64 ' s(33).maxdrive = 92 ' s(34).maxdrive = 92 ' s(35).maxdrive = 92 ' ' s(36).maxdrive = 92 ' s(37).maxdrive = 96 ' s(38).maxdrive = 72 ' s(39).maxdrive = 54 ' ' s(40).maxdrive = 25 ' s(41).maxdrive = 19 ' s(42).maxdrive = 20 ' s(43).maxdrive = 20 ' ' s(44).maxdrive = 18 ' s(45).maxdrive = 10 ' s(46).maxdrive = 10 ' s(47).maxdrive = 6 ' manual corrections: s(10).ventiel = 0 s(22).ventiel = 0 ' open pedal s(34).ventiel = 0 ' octave s(41).ventiel = 0 ' fifth s(46).ventiel = 0 ' double octave s(9).ventiel = 1 ' s(21).ventiel = 1 ' first valve open pedal s(33).ventiel = 1 ' octave s(40).ventiel = 1 ' fifth s(45).ventiel = 1 ' double octave s(8).ventiel = 2 ' s(20).ventiel = 2 ' second valve open pedal s(32).ventiel = 2 ' octave s(39).ventiel = 2 ' fifth s(44).ventiel = 2 ' double octave s(7).ventiel = 3 ' s(19).ventiel = 3 ' first + second valve open pedal s(31).ventiel = 3 ' octave s(38).ventiel = 3 ' fifth s(43).ventiel = 3 ' double octave s(6).ventiel = 4 ' s(18).ventiel = 4 ' third valve open pedal s(30).ventiel = 4 ' octave s(37).ventiel = 4 ' fifth s(42).ventiel = 4 ' double octave s(5).ventiel = 5 ' s(17).ventiel = 5 ' third and first valve open pedal s(29).ventiel = 5 ' octave s(36).ventiel = 5 ' fifth 's(41).ventiel = 5 ' double octave s(4).ventiel = 6 ' s(16).ventiel = 6 ' third and second valve open pedal s(28).ventiel = 6 ' octave s(35).ventiel = 6 ' fifth 's(40).ventiel = 6 ' double octave s(47).ventiel = 6 ' fifth above double octave s(3).ventiel = 7 ' s(15).ventiel = 7 ' first, third and second valve open pedal s(27).ventiel = 7 ' octave 's(34).ventiel = 7 ' fifth 's(39).ventiel = 7 ' double octave IF (param AND %So_Empirical)= %So_Empirical THEN ' empirical lookup table: ' s(8).ventiel = &B0000 ' used for external drive of membrane ' s(9).ventiel = &B0000 ' nc ' s(10).ventiel = &B0000 ' nc ' s(11).ventiel = &B0000 ' nc s(0).ventiel = &B0111 s(1).ventiel = &B0111 s(2).ventiel = &B0111 s(3).ventiel = &B0111 s(4).ventiel = &B0110 s(5).ventiel = &B0111 s(6).ventiel = &B0011 s(7).ventiel = &B0111 s(8).ventiel = &B0110 s(9).ventiel = &B0011 s(10).ventiel = &B0011 s(11).ventiel = &B0011 ' empirical values checked for best resonance 15.08.2003: s(12).ventiel = &B0111 s(13).ventiel = &B0111 s(14).ventiel = &B0111 s(15).ventiel = &B0111 s(16).ventiel = &B0110 s(17).ventiel = &B0111 s(18).ventiel = &B0011 s(19).ventiel = &B0111 s(20).ventiel = &B0110 s(21).ventiel = &B0011 s(22).ventiel = &B0011 s(23).ventiel = &B0011 s(24).ventiel = &B0111 s(25).ventiel = &B0010 s(26).ventiel = &B0011 s(27).ventiel = &B0011 s(28).ventiel = &B0111 s(29).ventiel = &B0110 s(30).ventiel = &B0111 s(31).ventiel = &B0111 s(32).ventiel = &B0111 s(33).ventiel = &B0111 s(34).ventiel = &B0011 s(35).ventiel = &B0101 s(36).ventiel = &B0011 s(37).ventiel = &B0111 s(38).ventiel = &B0111 s(39).ventiel = &B0011 s(40).ventiel = &B0111 s(41).ventiel = &B0110 s(42).ventiel = &B0101 s(43).ventiel = &B0101 s(44).ventiel = &B0011 s(45).ventiel = &B0111 s(46).ventiel = &B0111 s(47).ventiel = &B0111 END IF ' set the latchbytes for each note: [So version up to june 2007] ' new version (after 21.08.03) ' FOR i = 0 TO 47 ' SELECT CASE i ' CASE 0 TO 7 ' s(i).latchadr = 0 ' not used ' s(i).latchdta = 0 ' ITERATE FOR ' CASE 8 TO 15 ' s(i).latchadr = 1 ' &B0000 0001 ' CASE 16 TO 23 ' s(i).latchadr = 2 ' &B0000 0010 ' CASE 24 TO 31 ' s(i).latchadr = 4 ' &B0000 0100 ' CASE 32 TO 39 ' s(i).latchadr = 8 ' &B0000 1000 ' CASE 40 TO 47 ' s(i).latchadr = 16 ' &B0001 0000 ' END SELECT ' ' bit swapping to convert 2 7bit inputs to a 8 bit data bus: ' IF (i MOD 8) < 7 THEN ' BIT SET s(i).latchdta, i MOD 8 ' &B0xxx xxxx ' BIT RESET s(i).latchadr, 6 ' &B000x xxxx ' ELSE ' BIT RESET s(i).latchdta,7 ' &B0000 0000 ' BIT SET s(i).latchadr, 6 ' &B010x xxxx ' END IF ' NEXT i FUNCTION = %True END FUNCTION '[EOF]