'**************************************************************** '* Name : Fa_Hub.BAS * '* Author : Godfried-Willem RAES * '* Notice : Copyleft (c) 2011 Logosoft Public Domain * '* Date : 30-04-2011 * '* Version : 2 - 09.03.2020 * '* Notes : Based On Ob-hub code model, V3.1 * '* motor functions moved to another board * '* Now the eye lights go with the playing. '**************************************************************** '15.10.2010: First version by us. ' PIC: 18F2525 On MidiHub board, motor, sensors, lites '18.10.2010: Further coding. ' Analog tilt sensor design with Penny + Giles device. ' For -60 degree to + 60 degree we should read values between 102 and 922 from the ADC ' For -45 degree to + 45 degree we should read values between 205 and 819 from the ADC ' reduced to 7 bits, with 64 as center value we get 25 and 102 as extremes for 45 degrees '23.10.2010: V2.1: much better, but we still oscilate on standstill. ' V2.3: try with varying the PWM frequency in function of traject '24.10.2010: V2.7 with integrator and hardware change: 270nF cap. between mosfets. '25.10.2010: V2.8 using trigonometric functions and taking into account climbing or falling ' movement. Integration left out. Suggestion of Kristof Lauwers... '26.10.2010: Further research and development. Works fine as far as traject is conscerned, but ' we still have overshoot.. V2.9: small slowdown added when approaching soll value. ' V3.1: ' This version works, but we have to control maxspeed with CC23 ' on vertical, without oscillation this value has to be 28 (in midi) ' on forward, it can be set to 56 ' speed of movement depends on this controller. '----------------------------------------------------------- '20.04.2011: Ob code, version 3.1 used as model for the Fa hub board ' pin assignations are a bit different though. Ob must have an earlier board version... ' motor parameters have to be changed. Its a very different mechanism after all. '25.04.2011: First tests on the actual robot. ' Lite0 has a strange behaviour. '26.04.2011: Start works on the motor coding. ' CC21 sets the minimum speed for the motor ' CC22 sets the soll-position (destination) ' CC23 sets the maximum speed for the motor '30.04.2011: odd bug: on startup, some lights are flashing... ' Implemented: Timer3 as clock source for periodic sensor sampling at 64S/s ' Now version 1.3 ' seems working, bit eye light 4 (right eye) no longer functioning... ' we maybe have to clear bit 5 in SSPCON1 ' no, we did bend a PIC pin... '01.05.2011: Version 1.4: with sampling in the low priority interrupt. '18.05.2011: The lights do not always flash in a periodic way. There are standstills for some reason.... '21.05.2011: minimal integration added in low interupt on ADC. Motor movement code changed, leaving out ' angle calculations. Now version 1.5 '22.05.2011: testing. IRQ code changed to account for full timer period mistakes every so often. ' irregularities do remain... '23.05.2011: Version 1.6: Cnt.word0 clear in the IRQ : this is a substantial improvement. ' However, small short glitches still seem to occur. ' IRQ handler include file renamed to Fa_Hub_Irq ' Motor coding refined. Now using 8-bit resolutions. ' periodic timers seem to work to perfection now. '25.05.2011: Further work on motor coding. ' 2016 : Motor control moved to a new board. '----------------------------------------------------------------- '09.03.2020: Work on version V2: automated eye-lights. ' Coding adapted to newest Proton Compiler version. ' Test on testboard passed. Include "18F2525.inc" 'version for the fa board. (40MHz) 'Include "18F2520.inc" 'also possible. (40MHz) 'Include "18F25K20.inc" 'for test & debug on an Amicus board. (64MHz) ' Mapping defines for midi-events on pin outputs and inputs: ' lights: $define Yellow0 PORTC.5 ' X11-2 $define Yellow1 PORTC.4 ' X11-3 $define Red0 PORTB.0 ' X12-2 $define Red1 PORTB.1 ' X12-3 $define Blue0 PORTC.3 ' X15-2 eye right $define Blue1 PORTC.0 ' X15-3 eye left $define BlueLed PORTA.3 ' CC69 indicator $define GreenLed PORTA.4 ' CC66 indicator $define YellowLed PORTA.5 ' for code monitoring and debug ' $define Sensor PORTA.0 'input port - Penny& Giles tilt sensor 'red LED for debug: $define Debug_Led PORTB.5 ' for testing - red led - watchdog ' configure the input and output pins: Clear SSPCON1.5 'RC3 must be available for I/O TRISA = %01000111 'bits set to 0 are output, 1 = input TRISB = %11100000 TRISC = %11000000 'RC1 en RC2 zijn pwm outputs and must be set to output 'RC6 en RC7 zijn USART I/O and must be set to input 'constant definitions: 'initialisations for the midi input parser: Symbol Midichannel = 15 ' Fa_Channel Symbol NoteOff_Status = 128 + Midichannel ' 2 bytes follow Symbol NoteOn_Status = 144 + Midichannel Symbol Keypres_Status = 160 + Midichannel ' 2 bytes follow Symbol Control_Status = 176 + Midichannel Symbol ProgChange_Status = 192 + Midichannel ' 1 byte message Symbol Aftertouch_Status = 208 + Midichannel ' 1 byte follows Symbol Pitchbend_Status = 224 + Midichannel ' lsb msb follow 'application specific constants Symbol NrTasks = 7 ' eigenlijk zijn er NrTasks - 1 Symbol Eye_Time = 8192 ' ca. 180ms, as on Symbol LowTes = 34 Symbol Hightes = 91 ' Fa sounds only good up to note 79. up to 91 is implemented on the ARM board ' Setup the USART Declare Hserial_Baud = 31250 ' Set baud rate for the USART to MIDI specs. This must be 31250 For MIDI Declare Hserial_TXSTA = 0x24 ' instead of the normal 0x20 - ?? 0x24 Declare All_Digital = True ' Declare Hserial_Clear = On ' should clear on errors. Bytes get lost of course... ' Create variables Dim Cnt As Dword System Dim CntHw As Cnt.Word1 'used in the timer0 interrupt, to create a 32 bit timer Dim CntLw As TMR0L.Word 'this is the trick to read both TMR0L and TMR0H 'it makes Cntlw the low word of cnt 'We still have to copy the contents of Lw to Cnt Dim time As Cnt 'alias Dim maxtim As time.31 ' overflow bit, will cause timer reset after 1h45 Dim Bytein As Byte System ' midi byte read from buffer Dim MidiIn As Byte System Dim StBit As Bytein.7 ' highest bit of ByteIn Dim i As Byte System ' general purpose counter Dim j As Word Dim Tim3 As TMR3L.Word ' 16 bit counter for sampler ' Dim Sr as TMR0L.7 '512 S/s ' As TMR0H.1 would be 128 S/s ' As TMR0H.2 would be 64 S/s ' As TMR0H.3 would be 32 S/s ' As TMR0H.4 would be 16 S/s ' midi variables Dim statusbyte As Byte System Dim noteUit As Byte System ' note off + release value Dim release As Byte System Dim noteAan As Byte System ' note on + release value Dim velo As Byte System Dim notePres As Byte System ' note pressure + pressure value Dim pres As Byte System Dim Ctrl As Byte System ' continuous controller + value Dim value As Byte System Dim prog As Byte System ' program change + program-byte Dim aft As Byte System ' channel aftertouch Dim pblsb As Byte System ' pitch bend lsb Dim pbmsb As Byte System ' pitch bend msb Dim veltim As Dword System ' 32 bit velo Dim newtim As Dword System Dim Timvals[NrTasks] As Dword ' 09.03.2020 Dim Resort As Byte System Dim Resort_flag As Resort.0 ' flag to signal the requirement to resort timers ' Dim CC21 As Byte System ' motor minimum speed pwm - midi value ' Dim CC22 As Byte System ' motor soll-position - midi value ' Dim CC23 As Byte System ' motor maximum speed pwm - midi value Dim CC66 As Byte System ' global on/off switch Dim CC69 As Byte System Dim PowerOn As CC66.0 Dim st As Byte System Dim b1 As Byte System Dim b2 As Byte System Dim Lites As Byte System ' bits used as flags Dim idx As Byte System Dim nxt As Dword System ' Dim playingnote As Byte ' new 23.02.2020 Dim Vels[NrTasks] As Byte Dim IndexIn As Byte System Dim Indexout As Byte System Dim Ringbuffer[256] As Byte Dim Dur[128] As Word '----------------------------------------------------------------------------------------- ' Load the USART Interrupt handler And buffer read subroutines into memory 'Include "ADC.inc" ' Load the ADC macros into the program Include "Fa_Hub_Irq_V2.inc" ' our own version for UART And Timer0/3 Interrupt 'make sure we initialize those pins on start up: 'fault?: there should be no executable statements outside the main program. Low Yellow0 'midi note 0 Low Yellow1 Low Red0 Low Red1 Low Blue0 'midi note 4 Low Blue1 'midi note 5 Low Debug_Led HPWM 2, 255, PWMminF ' - RC1 PWM uses timer2 HPWM 1, 255, PWMminF ' - connected to RC2 Low GreenLed Low YellowLed High BlueLed Clear CC66 Set CC69 GoSub Dur_Lookup '----------------------------------------------------------------------------------------- ' Main program starts here MAIN: High Debug_Led DelayMS 50 ' wait for stability Low Debug_Led ' Clear VelFlags0 Set Timvals ' all timers off Clear idx Clear Lites GoSub Init_Usart_Interrupt ' Initiate the USART serial buffer interrupt ' this procedure is in the include file GoSub Clear_Serial_Buffer ' Clear the serial buffer and reset its pointers ' in the include as well ' Configure Timer0 for: ' Clear TMR0L and TMR0H registers ' Interrupt on Timer0 overflow ' 16-bit operation ' Internal clock source 40MHz ' 1:256 Prescaler : thus 40MHz / 256 = 156.250kHz ' Opentimer0 (Timer_INT_On & T0_16BIT & T0_SOURCE_INT & T0_PS_1_256) in macro file. Clear T1CON Clear IntConBits_T0IF ' clear interrupt flag Set INTCONBITS_T0IE ' enable interrupt on overflow T0CON = %10000111 ' bit 7 = enable/disable ' bit 6 = 1=8 bot, 0=16 bit ' bit 5 = 1 pin input, 0= Internal Clk0 ' bit 4 = HL or LH transition when bit5 =1 ' bit 3 = 1= bypass prescaler, 0= input from prescaler ' bit 2-0 = prescaler select: 111= 1:256 ' Setup the High priorities for the interrupts ' Open the ADC: ' Fosc/32 ' Right justified for 10-bit operation ' Tad value of 0 ' Vref+ at Vcc : Vref- at Gnd ' Make AN0 an analogue input ' ' OpenADC(ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_0_TAD, ADC_REF_VDD_VSS, ADC_1ANA) ' could be replaced with: ' ADCON2 = %10000010 ' ADCON1 = %00001110 ' ADCON0 = %00000001 ' SensorVal = ReadADC 0 ' initialize with the value on startup ' open and start timer3 for sampling: Clear T3CON Clear PIR2BITS_TMR3IF ' clear IRQ flag Set PIE2BITS_TMR3IE ' irq on Clear Tim3 ' Clear TMR3L And TMR3H registers Set RCONbits_IPEN ' Enable priority interrupts Clear IPR2bits_TMR3IP ' Set Timer3 as a low priority interrupt source ' we can also set T3Con in one instruction as: T3CON = %10110001 ' oef, now it works... ' bit 7 = 16 bit mode ' bit 6,3 = 0, 0 ' bit 5,4 = 1:8 prescale ' bit 2 = 0 ' bit 1 = 0 Internal clock = Fosc/4 ' bit 0 : 1= enable timer 3, 0= disable ' maximum count = 52.42ms, 1 tick =0.8uS HRSOut Ctrl, 66, 64 ' dummy, 2019 ' start the main program loop: Do ' Create an infinite loop Cnt.Word0 = CntLw ' read timer, note time is an alias for Cnt GetMidiIn () Bytein = MidiIn ' Read data from the serial buffer, with no timeout ' Start the midi parser. Midi_Parse: If Bytein > Control_Status Then ' here higher statusses are not implemented on this board If Bytein > 253 Then '254 = midiclock, 255= reset 'midiclock can interrupt all other msg's... '255 had to be intercepted since thats what we 'get when no new byte flows in (?) GoTo Check_Timers 'throw away... Else Clear statusbyte 'reset the status byte GoTo Check_Timers 'throw away End If EndIf If StBit =1 Then 'should be faster than If Bytein > 127 Then 'status byte received, bit 7 is set Clear statusbyte 'if on another channel, the statusbyte needs a reset Select Bytein 'eqv to Select case ByteIn Case NoteOff_Status statusbyte = Bytein Set noteUit 'reset value. Cannot be 0 !!! Set release '0 is a valid midi note! Case NoteOn_Status statusbyte = Bytein Set noteAan Set velo Case Keypres_Status 'used for lights statusbyte = Bytein Set notePres Set pres Case Control_Status ' this is the main thing to listen to.... statusbyte = Bytein Set Ctrl Set value ' Case ProgChange_Status ' statusbyte = Bytein ' prog = 255 ' Case Aftertouch_Status ' statusbyte = Bytein ' aft = 255 ' Case Pitchbend_Status ' statusbyte = Bytein ' pblsb = 255 ' pbmsb = 255 End Select Else 'midi byte is 7 bits Select statusbyte Case 0 'not a message for this channel GoTo Check_Timers 'disregard Case NoteOff_Status If noteUit = 255 Then noteUit = Bytein Else release = Bytein 'message complete, so we can do the action... Select noteUit Case 0 Clear Lites.0 Set Timvals[0] Set Resort_flag Clear Yellow0 ' one machine cycle only Case 1 Clear Lites.1 Set Timvals[1] Set Resort_flag Clear Yellow1 Case 2 Clear Lites.2 Set Timvals[2] Set Resort_flag Clear Red0 Case 3 Clear Lites.3 Set Timvals[3] Set Resort_flag Clear Red1 Case 4 Clear Lites.4 Set Timvals[4] Set Resort_flag Clear Blue0 Case 5 Clear Lites.5 Set Timvals[5] Set Resort_flag Clear Blue1 Case LowTes To Hightes If CC69 = 255 Then Timvals[6] = time + Eye_Time Set Resort_flag EndIf EndSelect Set noteUit 'reset EndIf Case NoteOn_Status If noteAan = 255 Then noteAan = Bytein Else velo = Bytein If velo = 0 Then Select noteAan Case 0 Clear Lites.0 Set Timvals[0] Set Resort_flag Clear Yellow0 ' one machine cycle only Case 1 Clear Lites.1 Set Timvals[1] Set Resort_flag Clear Yellow1 Case 2 Clear Lites.2 Set Timvals[2] Set Resort_flag Clear Red0 Case 3 Clear Lites.3 Set Timvals[3] Set Resort_flag Clear Red1 Case 4 Clear Lites.4 Set Timvals[4] Set Resort_flag Clear Blue0 Case 5 Clear Lites.5 Set Timvals[5] Set Resort_flag Clear Blue1 Case LowTes To Hightes If CC69 = 255 Then Timvals[6] = time + Eye_Time Set Resort_flag EndIf EndSelect Else ' velo > 0 Select noteAan Case 0 Set Lites.0 If velo < 127 Then Timvals[0] = time + Dur[velo] Else Set Timvals[0] EndIf Vels[0] = velo Set Resort_flag Set Yellow0 Case 1 Set Lites.1 If velo < 127 Then Timvals[1] = time + Dur[velo] Else Set Timvals[1] EndIf Vels[1] = velo Set Resort_flag Set Yellow1 Case 2 Set Lites.2 If velo < 127 Then Timvals[2] = time + Dur[velo] Else Set Timvals[2] EndIf Vels[2] = velo Set Resort_flag Set Red0 Case 3 Set Lites.3 If velo < 127 Then Timvals[3] = time + Dur[velo] Else Set Timvals[3] EndIf Vels[3] = velo Set Resort_flag Set Red1 Case 4 If CC69 = 0 Then Set Lites.4 If velo < 127 Then Timvals[4] = time + Dur[velo] Else Set Timvals[4] EndIf Vels[4] = velo Set Resort_flag Set Blue0 EndIf Case 5 If CC69 = 0 Then Set Lites.5 If velo < 127 Then Timvals[5] = time + Dur[velo] Else Set Timvals[5] EndIf Vels[5] = velo Set Resort_flag Set Blue1 EndIf Case LowTes To Hightes If CC69 = 255 Then Set Timvals[6] ' cancel timer Set Resort_flag Set Blue0 ' oogjes aan Set Blue1 EndIf EndSelect EndIf Set noteAan 'reset EndIf Case Keypres_Status 'used for lite flashing speed modulation If notePres = 255 Then notePres = Bytein Else pres = Bytein GoSub KeyPres EndIf Case Control_Status 'this is where the action takes place for controllers If Ctrl = 255 Then Ctrl = Bytein Else value = Bytein GoSub Controller EndIf ' Case ProgChange_Status ' If prog = 255 Then 'single byte message ' prog = Bytein ' GoSub ProgChange ' EndIf End Select EndIf If Resort_flag = 1 Then GoSub SortTimers ' so we resort only if an incoming midi command changed something with the timers EndIf Check_Timers: If idx < NrTasks Then ' we moeten alleen checken wanneer er een timer loopt If time >= nxt Then ' nagaan of de eerstvolgende timer afgelopen is... ' in dit geval is de eerste timer afgelopen en moeten we de juiste aktie ondernemen: Set nxt.31 ' timer reset, is immers afgelopen ' aan de hand van idx weten we welke timer dit is Select idx Case 0 Btg Yellow0 'Timvals[0] = time + Dur[Vels[0]] ' dit slikt de kompiler niet... j = Vels[0] Timvals[0] = time + Dur[j] Case 1 Btg Yellow1 j = Vels[1] Timvals[1] = time + Dur[j] 'Rate1 Case 2 Btg Red0 j = Vels[2] Timvals[2] = time + Dur[j] 'Rate2 Case 3 Btg Red1 j = Vels[3] Timvals[3] = time + Dur[j] 'Rate3 Case 4 If CC69 = 0 Then Btg Blue0 j = Vels[4] Timvals[4] = time + Dur[j] 'Rate4 Else Set Timvals[4] EndIf Case 5 If CC69 = 0 Then Btg Blue1 j = Vels[5] Timvals[5] = time + Dur[j] 'Rate5 Else Set Timvals[5] EndIf Case 6 ' used for switching off the eyes after a note-off ' should only happen when CC69 = 255 ' the timer is set on note-offs Set Timvals[6] Clear Blue0 Clear Blue1 'Case Else ' ' in dit geval is idx geset ' GoTo jumpout EndSelect GoSub SortTimers ' find a new nxt and idx EndIf ' beveiliging tegen overflow crashes... If maxtim = 1 Then Clear time Clear Lites Set Timvals EndIf Else ' idx > 13, no timers running, so to avoid overflows, we can reset the loop timer If maxtim = 1 Then Clear time ' 16.06.2015 EndIf ' average loop-speed: (Tektronix measurement) ' 5.5 us under no load up to 10us jittering under full load Loop SortTimers: 'look up the next smallest timer value in the Timvals array ' zoek de de volgende kleinste timer waarde: Set idx ' makes it 255 Set nxt.31 ' nxt is set on entry. - for speed, we just set the highest bit For i = 0 To NrTasks - 1 If Timvals[i] < nxt Then nxt = Timvals[i] ' 8 dword comparisons idx = i EndIf Next i Return KeyPres: 'the note to which the pressure should be applied is passed in NotePres, the value in Pres 'here we use it for flashing lights on Fa. Select notePres Case 0 If Lites.0 = 1 Then Timvals[0] = time + Dur[pres] Vels[0] = pres Else Set Timvals[0] Clear Yellow0 EndIf Set Resort_flag Case 1 If Lites.1 = 1 Then Timvals[1] = time + Dur[pres] Vels[1] = pres Else Set Timvals[1] Clear Yellow1 EndIf Set Resort_flag Case 2 If Lites.2 = 1 Then Timvals[2] = time + Dur[pres] Vels[2] = pres Else Set Timvals[2] Clear Red0 EndIf Set Resort_flag Case 3 If Lites.3 = 1 Then Timvals[3] = time + Dur[pres] Vels[3] = pres Else Set Timvals[3] Clear Red1 EndIf Set Resort_flag Case 4 If Lites.4= 1 Then Timvals[4] = time + Dur[pres] Vels[4] = pres Else Set Timvals[4] Clear Blue0 EndIf Set Resort_flag Case 5 If Lites.5 = 1 Then Timvals[5] = time + Dur[pres] Vels[5] = pres Else Set Timvals[5] Clear Blue1 EndIf Set Resort_flag EndSelect Set notePres '= 255 Return ProgChange: Set prog '= 255 'this is not realy required Return Pitchbend: 'only implemented on dsPIC based robots Set pblsb '= 255 Return Aftertouch: 'this is the channel aftertouch, affecting all notes Set aft '= 255 'not mandatory Return Controller: Select Ctrl Case 66 'on/off for the robot If value = 0 Then Clear PowerOn 'CC66.0 GoSub PowerDown Clear GreenLed Else Set PowerOn 'CC66.0 Set GreenLed EndIf Set CC69 Set BlueLed Case 69 If value < 64 Then Clear CC69 Clear BlueLed Else Set CC69 Set BlueLed EndIf Case 123 GoSub AllNotesOff EndSelect Set Ctrl 'mandatory reset Return AllNotesOff: 'stop all running timers Set Timvals Clear Yellow0 Clear Yellow1 Clear Red0 Clear Red1 Clear Blue0 Clear Blue1 Clear Lites Return PowerDown: 'stop all running timers Set Timvals Clear Yellow0 Clear Yellow1 Clear Red0 Clear Red1 Clear Blue0 Clear Blue1 Clear Lites Return Dur_Lookup: 'this lookup is for a good scaling of the velocity byte on event periodicity ' the values are calculated based on a timer resolution of 24 microseconds. ' The values must be containable in a word (16 bits!) ' This is the simple Power Basic program wherewith the lookup was calculated: 'FUNCTION PBMAIN ()AS LONG ' OPEN "Whisper_Dur_scales.inc" FOR OUTPUT AS #1 ' LOCAL unit, fastest, slowest, velo_traject AS DOUBLE ' LOCAL velo, i AS DWORD ' unit = 0.000024 ' in seconds (24 microseconds) ' fastest = 1 / 16 ' 16 Hz ' slowest = 1.5 ' 0.66 Hz ' velo_traject = slowest - fastest ' PRINT# 1, "Lookup for Whisper durations in periodic events" ' FOR i = 1 TO 127 ' velo = velo_traject / i ' PRINT i; velo, ' PRINT# 1 ,"Dur[";i;"] ="; velo ' NEXT i 'DO: LOOP UNTIL INKEY$ <> "" 'END FUNCTION ' same lookup also used in Dur[ 1 ] = 59896 Dur[ 2 ] = 29948 Dur[ 3 ] = 19965 Dur[ 4 ] = 14974 Dur[ 5 ] = 11979 Dur[ 6 ] = 9983 Dur[ 7 ] = 8557 Dur[ 8 ] = 7487 Dur[ 9 ] = 6655 Dur[ 10 ] = 5990 Dur[ 11 ] = 5445 Dur[ 12 ] = 4991 Dur[ 13 ] = 4607 Dur[ 14 ] = 4278 Dur[ 15 ] = 3993 Dur[ 16 ] = 3743 Dur[ 17 ] = 3523 Dur[ 18 ] = 3328 Dur[ 19 ] = 3152 Dur[ 20 ] = 2995 Dur[ 21 ] = 2852 Dur[ 22 ] = 2723 Dur[ 23 ] = 2604 Dur[ 24 ] = 2496 Dur[ 25 ] = 2396 Dur[ 26 ] = 2304 Dur[ 27 ] = 2218 Dur[ 28 ] = 2139 Dur[ 29 ] = 2065 Dur[ 30 ] = 1997 Dur[ 31 ] = 1932 Dur[ 32 ] = 1872 Dur[ 33 ] = 1815 Dur[ 34 ] = 1762 Dur[ 35 ] = 1711 Dur[ 36 ] = 1664 Dur[ 37 ] = 1619 Dur[ 38 ] = 1576 Dur[ 39 ] = 1536 Dur[ 40 ] = 1497 Dur[ 41 ] = 1461 Dur[ 42 ] = 1426 Dur[ 43 ] = 1393 Dur[ 44 ] = 1361 Dur[ 45 ] = 1331 Dur[ 46 ] = 1302 Dur[ 47 ] = 1274 Dur[ 48 ] = 1248 Dur[ 49 ] = 1222 Dur[ 50 ] = 1198 Dur[ 51 ] = 1174 Dur[ 52 ] = 1152 Dur[ 53 ] = 1130 Dur[ 54 ] = 1109 Dur[ 55 ] = 1089 Dur[ 56 ] = 1070 Dur[ 57 ] = 1051 Dur[ 58 ] = 1033 Dur[ 59 ] = 1015 Dur[ 60 ] = 998 Dur[ 61 ] = 982 Dur[ 62 ] = 966 Dur[ 63 ] = 951 Dur[ 64 ] = 936 Dur[ 65 ] = 921 Dur[ 66 ] = 908 Dur[ 67 ] = 894 Dur[ 68 ] = 881 Dur[ 69 ] = 868 Dur[ 70 ] = 856 Dur[ 71 ] = 844 Dur[ 72 ] = 832 Dur[ 73 ] = 820 Dur[ 74 ] = 809 Dur[ 75 ] = 799 Dur[ 76 ] = 788 Dur[ 77 ] = 778 Dur[ 78 ] = 768 Dur[ 79 ] = 758 Dur[ 80 ] = 749 Dur[ 81 ] = 739 Dur[ 82 ] = 730 Dur[ 83 ] = 722 Dur[ 84 ] = 713 Dur[ 85 ] = 705 Dur[ 86 ] = 696 Dur[ 87 ] = 688 Dur[ 88 ] = 681 Dur[ 89 ] = 673 Dur[ 90 ] = 666 Dur[ 91 ] = 658 Dur[ 92 ] = 651 Dur[ 93 ] = 644 Dur[ 94 ] = 637 Dur[ 95 ] = 630 Dur[ 96 ] = 624 Dur[ 97 ] = 617 Dur[ 98 ] = 611 Dur[ 99 ] = 605 Dur[ 100 ] = 599 Dur[ 101 ] = 593 Dur[ 102 ] = 587 Dur[ 103 ] = 582 Dur[ 104 ] = 576 Dur[ 105 ] = 570 Dur[ 106 ] = 565 Dur[ 107 ] = 560 Dur[ 108 ] = 555 Dur[ 109 ] = 550 Dur[ 110 ] = 545 Dur[ 111 ] = 540 Dur[ 112 ] = 535 Dur[ 113 ] = 530 Dur[ 114 ] = 525 Dur[ 115 ] = 521 Dur[ 116 ] = 516 Dur[ 117 ] = 512 Dur[ 118 ] = 508 Dur[ 119 ] = 503 Dur[ 120 ] = 499 Dur[ 121 ] = 495 Dur[ 122 ] = 491 Dur[ 123 ] = 487 Dur[ 124 ] = 483 Dur[ 125 ] = 479 Dur[ 126 ] = 475 Dur[ 127 ] = 472 Return '[EOF]