Cross-platform MIDI in pure FreeBasic!

User projects written in or related to FreeBASIC.
angros47
Posts: 1421
Joined: Jun 21, 2005 19:04

Cross-platform MIDI in pure FreeBasic!

Postby angros47 » Dec 12, 2013 21:48

Since some users complained about the lack of a way to play MIDI files on all platforms (most solutions are windows-only), here is a solution.

Modern sound cards does not have midi-capable hardware, so a software synthesizer is needed; most software MIDI synthesizer produce sounds by playing pre-recorded samples: this solution is easy to implement, produce a realistic sound, but is really heavy in terms of memory and download size. So, a common solution is to replace MIDI files with MP3 (they are bigger, but they require no soundfonts so download size will still be small).

FM synthesis is an alternative, used on older sound cards, but also on synthesizers like the Yamaha DX 7; it can produce almost any sound, by using almost no memory and very little resources. The sound is a bit "electronic", but it's more than enough for most computer applications.

Some time ago, I used an OPL emulator written in C by Ken Silverman; anyway, it emulates perfectly most advantages of the old hardware... but also its limits: only one note per channel, only nine channels, only two operators.

I found a better solution here (http://milkpot.sakura.ne.jp/fmmidi/), and finally I managed to port it to FreeBasic: it is not an emulator of a specific hardware, so it has not the limitation of an OPL chip, although the algorithm used is similar (phase modulation of sine waves, lookup tables to speed up the process, an output buffer with PCM data).

It supports all 128 MIDI instruments, and percussions. Also, it's possible to change values in the array "programs", to define different instruments (defining a sound using FM parameters is much harder than defining it, i.e., with subtractive synthesis; fortunately, default instruments have already been defined)

You can turn on and off any note, on any channel; there is no limit to polyphony, and every instruments can use an algorithm based on 4 parameter FM synthesis.

But the synthesizer can just replace the MIDI driver: to be able to play MIDI files, a sequencer is needed, too; instead of porting the sequencer from C++ version of FMMIDI, I ported the sequencer written by Sebastian Mate for RealMidi: it's simpler, and easier to understand. It's more limited (it can't play multi-track files), but its main purpose is just to test the synthesizer.

Anyway, here is the files:
http://www27.zippyshare.com/v/9457100/file.html
angros47
Posts: 1421
Joined: Jun 21, 2005 19:04

Re: Cross-platform MIDI in pure FreeBasic!

Postby angros47 » Dec 12, 2013 21:53

Here is the source code (if zippyshare does not work)

MIDISYNTH.BAS

Code: Select all

 '
 ' Copyright(c)2007 yuno  --- Port to FreeBasic by Angelo Rosina
 '
 ' This software is provided 'as-is', without any express or implied warranty.
 ' In no event will the authors be held liable for any damages arising from the
 ' use of this software.
 '
 ' Permission is granted to anyone to use this software for any purpose,
 ' including commercial applications, and to alter it and redistribute it
 ' freely, subject to the following restrictions:
 '
 ' 1. The origin of this software must not be misrepresented; you must not claim
 ' that you wrote the original software. If you use this software in a product,
 ' an acknowledgment in the product documentation would be appreciated but is
 ' not required.
 '
 ' 2. Altered source versions must be plainly marked as such, and must not be
 ' misrepresented as being the original software.
 '
 ' 3. This notice may not be removed or altered from any source distribution.
 '


const LOG10_32767=4.5154366811416989472479934140484
const LOGTABLE_FACTOR=(4096 / LOG10_32767)

dim shared as short sine_table(4095)
dim shared as unsigned short log_table(4095)

type _envelope_table
     TL(127) as unsigned long
     SL(15,127) as unsigned long
     AR(63,127) as double
     RR(63,127) as double
end type

dim shared envelope_table as _envelope_table
dim shared as long vibrato_table(16383)

#include "midisynth.bi"
#include "instruments.bi"

sub InitTables() constructor
        for i as integer= 0 to 4095
            sine_table(i) = cast(short, sin(i * 2 * M_PI / 4096)*32767)
            log_table(i) = 10^ (cast(double,i) / LOGTABLE_FACTOR)
        next
        for t as integer=0 to 127
            dim as double fTL = 32767 * 10^(t * -0.75 / 10)
            envelope_table.TL(t) = fTL
            if envelope_table.TL(t) = 0 then
                envelope_table.TL(t) = 1
            end if
            for s as integer = 0 to 15
                dim as double x = fTL * 10^(s * -3.0 / 10)
                if x <= 1 then
                    envelope_table.SL(s,t) = 0
                else
                    envelope_table.SL(s,t) = 65536 * LOGTABLE_FACTOR * (log(x)/log(10))
                end if
            next
        next
        for x as integer = 0 to 63
            dim as double attack_time = 15.3262 * 10^(x * -0.75 / 10)
            dim as double release_time = 211.84 * 10^(x * -0.75 / 10)
            for t as integer = 0 to 127
                envelope_table.AR(x,t) = envelope_table.TL(t) / attack_time
                envelope_table.RR(x,t) = 65536 * LOGTABLE_FACTOR * 48.0 / 10 * envelope_table.TL(t) / 32767 / release_time
            next
        next
        for i as integer= 0 to 16383
            dim x as double = (cast(double,i) / 16384 - 0.5) * 256.0 / 12.0
            vibrato_table(i) = cast(long,(2^x - 1) * 65536.0)
        next


end sub


function channel.synthesize(out as long ptr, samples as uinteger, rate as single, master_volume as long, master_balance as integer) as integer
        dim volume as double
        if mute=0 then volume = (cast(double,master_volume) * this.volume * expression / (16383.0 * 16383.0 * 16383.0))^ 2 * 16383.0
        dim num_notes as integer
        dim i as _NOTES ptr= _firstnote
        while(i <> 0)
            dim as fm_note ptr note = i->note
            dim as ulong panpot = note->panpot
            if this.panpot <= 8192 then
                panpot = panpot * this.panpot / 8192
            else
                panpot = panpot * (16384 - this.panpot) / 8192 + (this.panpot - 8192) * 2
            end if
            if master_balance <= 8192 then
                panpot = panpot * master_balance / 8192
            else
                panpot = panpot * (16384 - master_balance) / 8192 + (master_balance - 8192) * 2
            end if

            if panpot<1 then panpot=0 else panpot-=1
            dim as long _left = cast(long,volume * cos(panpot * (M_PI / 2 / 16382)))
            dim as long _right = cast(long,volume * sin(panpot * (M_PI / 2 / 16382)))
            dim as integer ret = note->synthesize(out, samples, rate, _left, _right)
            if ret then
                i=i->_next
            else
                if i=this._firstnote then this._firstnote=i->_next
                if i=this._lastnote then this._lastnote=i->_prev
                if i->_next<>0 then i->_next->_prev=i->_prev
                if i->_prev<>0 then i->_prev->_next=i->_next

                delete note
                dim old as _NOTES ptr= i->_next
      delete i
                i=old
            end if
            num_notes+=1
        wend
        return num_notes
end function

sub channel.reset_all_parameters()
        program = default_bank * 128
        bank = default_bank
        panpot = 8192
        volume = 12800
        fine_tuning = 8192
        coarse_tuning = 8192
        tremolo_frequency = 3
        vibrato_frequency = 3
        master_frequency_multiplier = 1
        mono = 0
        mute = 0
        system_mode = 0'system_mode_default
        reset_all_controller()
end sub

sub channel.reset_all_controller()
        expression = 16383
        channel_pressure(0)
        pitch_bend = 8192
        pitch_bend_sensitivity = 256
        update_frequency_multiplier()
        modulation_depth = 0
        modulation_depth_range = 64
        update_modulation()
        set_damper(0)
        set_sostenute(0)
        set_freeze(0)
        RPN = &H3FFF
        NRPN = &H3FFF
end sub

sub channel.all_note_off()
   dim as _NOTES ptr i=this._firstnote
   do until i=0
            if i->status = 1 then
                i->status = 0
                i->note->fm.key_off()
            end if
            i=i->_next
        loop
end sub

sub channel.all_sound_off()
   dim as _NOTES ptr i=this._firstnote
   do until i=0
            if i->status <> -1 then
                i->status = -1
                i->note->fm.sound_off()
            end if
            i=i->_next
        loop
end sub

sub channel.all_sound_off_immediately()
   dim as _NOTES ptr i=this._firstnote
   do until i=0
            delete i->note
            i=i->_next
            if i->_prev<>0 then delete i->_prev
        loop
        this._firstnote=0
        this._lastnote=0
end sub

sub channel.note_on(note as integer, velocity as integer)

        note_off(note, 64)
        if velocity then
            if mono then
                all_sound_off()
            end if
            dim as fm_note ptr p = factory->note_on(program, note, velocity, frequency_multiplier)
            if p<>0 then
                dim as integer assign = p->assign
                if assign<>0 then
                    dim as _NOTES ptr i=this._firstnote
                    do until i=0
                        if i->note->assign = assign then
                            i->note->fm.sound_off()
                        end if
                        i=i->_next
                    loop
                end if
                if freeze then
                    p->fm.set_freeze(freeze)
                end if
                if damper then
                    p->fm.set_damper(damper)
                end if
                if modulation_depth then
                    dim as single depth = cast(double,modulation_depth) * modulation_depth_range / (16383.0 * 128.0)
                    p->fm.set_vibrato(depth, vibrato_frequency)
                end if
                if pressure then
                    p->fm.set_tremolo(pressure, tremolo_frequency)
                end if

                dim as _NOTES ptr pp=new _NOTES:
                pp->note=p: pp->key=note: pp->status=1
                if this._firstnote=0 then this._firstnote=pp:this._lastnote=pp else pp->_prev=this._lastnote:this._lastnote->_next=pp
                this._lastnote=pp

            end if
        end if
end sub

sub channel.note_off(note as integer, velocity as integer)
   dim as _NOTES ptr i=this._firstnote
   do until i=0
            if i->key = note andalso i->status = 1 then
                i->status = 0
                i->note->fm.key_off()
            end if
            i=i->_next
        loop
end sub

sub channel.polyphonic_key_pressure(note as integer, value as integer)
   dim as _NOTES ptr i=this._firstnote
   do until i=0
            if i->key = note andalso i->status = 1 then
                i->note->fm.set_tremolo(value, tremolo_frequency)
            end if
            i=i->_next
        loop
end sub

sub channel.channel_pressure(value as integer)
        if pressure <> value then
            pressure = value
       dim as _NOTES ptr i=this._firstnote
       do until i=0
                if i->status = 1 then
                    i->note->fm.set_tremolo(value, tremolo_frequency)
                end if
                i=i->_next
            loop
        end if
end sub

sub channel.control_change(control as integer, value as integer)
        select case control
        case &H00
            bank_select((bank and &H7F) or (value shl 7))
        case &H01
            modulation_depth=(modulation_depth and &H7F) or (value shl 7)
            update_modulation()
        case &H06
            set_registered_parameter((get_registered_parameter() and &H7F) or (value shl 7))
        case &H07
            volume = (volume and &H7F) or (value shl 7)
        case &H0A
            panpot = (panpot and &H7F) or (value shl 7)
        case &H0B
            expression = (expression and &H7F) or (value shl 7)
        case &H20
            bank_select((bank and &H7F) or (value shl 7))
        case &H21
            modulation_depth=(modulation_depth and not &H7F) or value
            update_modulation()
        case &H26
            set_registered_parameter((get_registered_parameter() and not &H7F) or value)
        case &H27
            volume = (volume and not &H7F) or value
        case &H2A
            panpot = (panpot and not &H7F) or value
        case &H2B
            expression = (expression and not &H7F) or value
        case &H40
            set_damper(value)
        case &H42
            set_sostenute(value)
        case &H45
            set_freeze(value)
        case &H60
            if get_registered_parameter() + 1>&H3FFF then
               set_registered_parameter(get_registered_parameter() + 1)
            else
               set_registered_parameter(&H3FFF)
            end if
        case &H61
            if get_registered_parameter() - 1<0 then
               set_registered_parameter(get_registered_parameter() - 1)
            else
               set_registered_parameter(0)
            end if
        case &H62
            NRPN=(NRPN and not &H7F) or value
            RPN = &H3FFF
        case &H63
            NRPN=(NRPN and &H7F) or (value shl 7)
            RPN = &H3FFF
        case &H64
            RPN=(RPN and not &H7F) or value
            NRPN = &H3FFF
        case &H65
            RPN=(RPN and &H7F) or (value shl 7)
            NRPN = &H3FFF
        case &H78
            all_sound_off()
        case &H79
            reset_all_controller()
        case &H7B, &H7C, &H7D
            all_note_off()
        case &H7E
            all_note_off(): mono = 1
        case &H7F
            all_note_off(): mono = 0
        end select
end sub

sub channel.bank_select(value as integer)
        select case system_mode
        case 1
        case 3
            if ((bank and &H3F80) = &H3C00) = ((value and &H3F80) = &H3C00) then
                bank=value
            end if
        case 4
            if default_bank = &H3C00 then
                bank=&H3C00 or (value and &H7F)
            elseif (value and &H3F80) = &H3F80 then
                bank=&H3C00 or (value and &H7F)
            else
                bank=value
            end if
        case else
            if default_bank = &H3C00 then
                bank=&H3C00 or (value and &H7F)
            else
                bank=value
            end if
        end select
end sub

sub channel.set_damper(value as integer)
        if damper <> value then
            damper = value
       dim as _NOTES ptr i=this._firstnote
       do until i=0
                i->note->fm.set_damper(value)
                i=i->_next
            loop
           
        end if
end sub

sub channel.set_sostenute(value as integer)
        sostenute = value
   dim as _NOTES ptr i=this._firstnote
   do until i=0
            i->note->fm.set_sostenute(value)
            i=i->_next
        loop
end sub

sub channel.set_freeze(value as integer)
        if freeze <> value then
            freeze = value
       dim as _NOTES ptr i=this._firstnote
       do until i=0
                i->note->fm.set_freeze(value)
                i=i->_next
            loop
        end if
end sub

function channel.get_registered_parameter() as integer
        select case RPN
        case &H0000
            return pitch_bend_sensitivity
        case &H0001
            return fine_tuning
        case &H0002
            return coarse_tuning
        case &H0005
            return modulation_depth_range
        case else
            return 0
        end select
end function

sub channel.set_registered_parameter(value as integer)
        select case RPN
        case &H0000
            pitch_bend_sensitivity=value
            update_frequency_multiplier()
        case &H0001
            fine_tuning=value
            update_frequency_multiplier()
        case &H0002
            coarse_tuning=value
            update_frequency_multiplier()
        case &H0005
            modulation_depth_range=value
            update_modulation()
        case else
        end select
end sub

sub channel.update_frequency_multiplier()
        dim as single value = master_frequency_multiplier * _
                    2^ ((coarse_tuning - 8192) / (128.0 * 100.0 * 12.0) _
                                + (fine_tuning - 8192) / (8192.0 * 100.0 * 12.0) _
                                + cast(double,pitch_bend - 8192) * pitch_bend_sensitivity / (8192.0 * 128.0 * 12.0))
        if frequency_multiplier <> value then
            frequency_multiplier = value
       dim as _NOTES ptr i=this._firstnote
       do until i=0
                i->note->fm.set_damper(value)
                i->note->fm.set_frequency_multiplier(value)
                i=i->_next
            loop
        end if
end sub

sub channel.update_modulation()
        dim as single depth = cast(double,modulation_depth) * modulation_depth_range / (16383.0 * 128.0)
   dim as _NOTES ptr i=this._firstnote
   do until i=0
            i->note->fm.set_vibrato(depth, vibrato_frequency)
            i=i->_next
        loop
end sub

function synthesizer.synthesize(_output as short ptr, samples as uinteger, rate as single) as integer
        dim as uinteger n = samples * 2
        dim as long buf(n+1)
        dim as integer num_notes = synthesize_mixing(@buf(0), samples, rate)
        if num_notes then
            for i as uinteger = 0 to n
                dim as long x = buf(i)
                if x < -32767 then
                    _output[i] = -32767
                elseif x > 32767 then
                    _output[i] = 32767
                else
                    _output[i] = x
                end if
            next
        else
            clear _output[0], 0, len(short) * n
        end if
        return num_notes
end function

function synthesizer.synthesize_mixing(_output as long ptr, samples as uinteger, rate as single) as integer
        if active_sensing = 0 then
            all_sound_off()
            active_sensing = -1
        elseif active_sensing > 0 then
            active_sensing -= samples / rate
            if active_sensing < 0 then active_sensing=0
        end if
        dim as long volume = cast(long,main_volume) * master_volume / 16384
        dim as integer num_notes = 0
        for i as integer = 0 to 15
            num_notes += channels(i).synthesize(_output, samples, rate, volume, master_balance)
        next
        return num_notes
end function

sub synthesizer.reset()
   for i as integer=0 to 15
      if channels(i).factory=0 then channels(i).factory= new fm_note_factory
      for a as integer=0 to 128
         channels(i).factory->programs(a)=@programs(a)
      next
      for a as integer=35 to 81
         channels(i).factory->drums(a)=@drums(a)
      next

   next

        all_sound_off_immediately()
        reset_all_parameters()
end sub

sub synthesizer.reset_all_parameters()
        active_sensing = -1
        main_volume = 8192
        master_volume = 16383
        master_balance = 8192
        master_fine_tuning = 8192
        master_coarse_tuning = 8192
        master_frequency_multiplier = 1
        system_mode = 0
        for i as integer = 0 to 15
            channels(i).reset_all_parameters()
        next
end sub

sub synthesizer.reset_all_controller()
        for i as integer = 0 to 15
            channels(i).reset_all_controller()
        next
end sub

sub synthesizer.all_note_off()
        for i as integer = 0 to 15
            channels(i).all_note_off()
        next
end sub

sub synthesizer.all_sound_off()
        for i as integer = 0 to 15
            channels(i).all_sound_off()
        next
end sub

sub synthesizer.all_sound_off_immediately()
        for i as integer = 0 to 15
            channels(i).all_sound_off_immediately()
        next
end sub

sub synthesizer.sysex_message(pvdata as string)
        if left(pvdata,6)= !"\xF0\x7E\x7F\x09\x01\xF7" then
            ' GM system on
            set_system_mode(1)
        elseif left(pvdata,6) =!"\xF0\x7E\x7F\x09\x02\xF7" then
            ' GM system off
            set_system_mode(2)
        elseif left(pvdata,6)=!"\xF0\x7E\x7F\x09\x03\xF7" then
            ' GM2 system on
            set_system_mode(2)
        elseif left(pvdata,2)= !"\xF0\x41" andalso mid(pvdata,4,8)= !"\x42\x12\x40\x00\x7F\x00\x41\xF7" then
            ' GS reset
            set_system_mode(3)
        elseif left(pvdata,2)= !"\xF0\x43" andalso (asc(pvdata,3) and &HF0) = &H10 andalso mid(pvdata, 4, 6)= !"\x4C\x00\x00\x7E\x00\xF7" then
            ' XG system on
            set_system_mode(4)
        elseif left(pvdata, 5) =!"\xF0\x7F\x7F\x04\x01" andalso asc(pvdata,8) = &HF7 then
            ' master volume
            master_volume=(asc(pvdata,6) and &H7F) or ((asc(pvdata,7) and &H7F) shl 7)
        elseif left(pvdata,5) = !"\xF0\x7F\x7F\x04\x02" andalso asc(pvdata,8) = &HF7 then
            ' master balance
            master_balance=(asc(pvdata,6) and &H7F) or ((asc(pvdata,7) and &H7F) shl 7)
        elseif left(pvdata,5) = !"\xF0\x7F\x7F\x04\x03" andalso asc(pvdata,8) = &HF7 then
            ' master fine tuning
            master_fine_tuning=(asc(pvdata,6) and &H7F) or ((asc(pvdata,7) and &H7F) shl 7)
            update_master_frequency_multiplier()
        elseif left(pvdata,5) = !"\xF0\x7F\x7F\x04\x04" andalso asc(pvdata,8) = &HF7 then
            ' master coarse tuning
            master_coarse_tuning=(asc(pvdata,6) and &H7F) or ((asc(pvdata,7) and &H7F) shl 7)
            update_master_frequency_multiplier()
        elseif left(pvdata, 2) = !"\xF0\x41" andalso (asc(pvdata,3) and &HF0) = &H10 andalso mid(pvdata, 4, 3) = !"\x42\x12\x40"andalso (asc(pvdata,7) and &HF0) = &H10 andalso asc(pvdata,8) = &H15 andalso asc(pvdata,11) = &HF7 then
            ' use for rhythm part
            dim as integer _channel = asc(pvdata,7) and &H0F
            if asc(pvdata,9) = 0 then
                channels(_channel).bank=&H3C80
            else
                channels(_channel).bank=&H3C00
            end if
            channels(_channel).program=128*channels(_channel).bank
        end if
end sub

sub synthesizer.midi_event(event as integer, param1 as integer, param2 as integer)
        select case (event and &HF0)
        case &H80
            channels(event and &H0F).note_off(param1 and &H7F, param2 and &H7F)
        case &H90
            channels(event and &H0F).note_on(param1 and &H7F, param2 and &H7F)
        case &HA0
            channels(event and &H0F).polyphonic_key_pressure(param1 and &H7F, param2 and &H7F)
        case &HB0
            channels(event and &H0F).control_change(param1 and &H7F, param2 and &H7F)
        case &HC0
            channels(event and &H0F).program=(param1 and &H7F)+128*channels(event and &H0F).bank
        case &HD0
            channels(event and &H0F).channel_pressure(param1 and &H7F)
        case &HE0
            channels(event and &H0F).pitch_bend=((param2 and &H7F) shl 7) or (param1 and &H7F)
            channels(event and &H0F).update_frequency_multiplier()
        case &HFE
            active_sensing = 0.33
        case &HFF
            all_sound_off()
            reset_all_parameters()
        case else
        end select
end sub

sub synthesizer.set_system_mode(mode as integer)
        all_sound_off()
        reset_all_parameters()
        system_mode = mode
        for i as integer=0 to 15
            channels(i).system_mode=mode
        next
end sub

sub synthesizer.update_master_frequency_multiplier()
        dim as single value = 2^( (master_coarse_tuning - 8192) / (128.0 * 100.0 * 12.0)_
                                + (master_fine_tuning - 8192) / (8192.0 * 100.0 * 12.0))
        if master_frequency_multiplier <> value then
            master_frequency_multiplier = value
            for i as integer=0 to 15
                channels(i).master_frequency_multiplier=value
                channels(i).update_frequency_multiplier
            next
        end if
end sub

sub sine_wave_generator.set_cycle(cycle as single)
        if cycle<>0 then
            _step = cast(unsigned long, 4096.0 * 32768.0 / cycle)
        else
            _step = 0
        end if
end sub

sub sine_wave_generator.add_modulation(x as long)
        position += cast(long, cast(longint, _step) * x shr 16)
end sub

function sine_wave_generator.get_next() as integer
        position += _step
        return sine_table((position / 32768) mod 4096)
end function

function sine_wave_generator.get_next(modulation as long) as integer
        position += _step
        dim as long m = modulation * 4096 / 65536
        dim as ulong p = cast(ulong,(position  / 32768 + m)) mod 4096
        return sine_table(p)
end function

sub envelope_generator.set_rate(rate as single)
        if rate<>0 then this.rate = rate else this.rate=1
        update_parameters()
end sub

sub envelope_generator.set_hold(hold as single)
        if this.hold > hold orelse state <= SUSTAIN orelse current >= fSL then
            this.hold = hold
            update_parameters()
        end if
end sub

sub envelope_generator.set_freeze(freeze as single)
        if this.freeze > freeze orelse state <= SUSTAIN orelse current >= fSL then
            this.freeze = freeze
            update_parameters()
        end if
end sub

sub envelope_generator.update_parameters()
        dim as double fAR = envelope_table.AR(AR,TL) / rate
        dim as double fDR = envelope_table.RR(DR,TL) / rate
        dim as double fSR = envelope_table.RR(SR,TL) / rate
        dim as double fRR = envelope_table.RR(RR,TL) / rate

        if fRR < 1 then
            fRR = 1
        end if
        if hold > 0 then
            fRR = fSR * hold + fRR * (1 - hold)
        end if
        if freeze > 0 then
            fDR *= 1 - freeze
            fSR *= 1 - freeze
            fRR *= 1 - freeze
        end if
        if fAR < 1 then
            fAR = 1
        end if
        this.fAR = cast(unsigned long,fAR)
        this.fDR = cast(unsigned long,fDR)
        this.fSR = cast(unsigned long,fSR)
        this.fRR = cast(unsigned long,fRR)
        this._fOR = cast(unsigned long,envelope_table.RR(63,0) / rate)
        if this.fDR>fSL then this.fSS = this.fDR else this.fSS = fSL
        if this.fDR>this.fRR then this.fDRR = this.fDR else this.fDRR = this.fRR
        if this.fDRR>this.fSS then this.fDSS = this.fDRR else this.fDSS = this.fSS
end sub

sub envelope_generator.key_off()
        select case state
        case ATTACK
            state = ATTACK_RELEASE
        case DECAY
            state = DECAY_RELEASE
        case SUSTAIN
            state = RELEASE
        case else
        end select
end sub

sub envelope_generator.sound_off()
        select case state
        case ATTACK, ATTACK_RELEASE
            if current<>0 then
                current = 65536 * LOGTABLE_FACTOR * log(cast(double,current))/log(10)
            end if
        case else
        end select
        state = SOUNDOFF
end sub

function envelope_generator.get_next() as integer
        dim as unsigned long current = this.current
        select case state
        case ATTACK
            if current < fTL then
                this.current = current + fAR
                return this.current
            end if
            this.current = 65536 * LOGTABLE_FACTOR * log(cast(double,fTL))/log(10)
            state = DECAY
            return fTL
        case DECAY
            if current > fSS then
                current -= fDR
                this.current = current
                return log_table(current / 65536)
            end if
            current = fSL
            this.current = current
            state = SUSTAIN
            return log_table(current / 65536)
        case SUSTAIN
            if current > fSR then
                current -= fSR
                this.current = current
                dim n as integer = log_table(current / 65536)
                if n > 1 then
                    return n
                end if
            end if
            state = FINISHED
            return 0
        case ATTACK_RELEASE
            if current < fTL then
                this.current = current + fAR
                return this.current
            end if
            this.current = 65536 * LOGTABLE_FACTOR * log(cast(double,fTL))/log(10)
            state = DECAY_RELEASE
            return fTL
        case DECAY_RELEASE
            if current > fDSS then
                current -= fDRR
                this.current = current
                return log_table(current / 65536)
            end if
            current = fSL
            this.current = current
            state = RELEASE
            return log_table(current / 65536)
        case RELEASE
            if current > fRR then
                current -= fRR
                this.current = current
                dim n as integer = log_table(current / 65536)
                if n > 1024 then
                    return n
                end if
                state = SOUNDOFF
                return n
            end if
            state = FINISHED
            return 0
        case SOUNDOFF
            if current > _fOR then
                current -= _fOR
                this.current = current
                dim n as integer = log_table(current / 65536)
                if n > 1 then
                    return n
                end if
            end if
            state = FINISHED
            return 0
        case else
            return 0
        end select
end function

dim shared as integer keyscale_table(3,127) = {_
            {_
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,_
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,_
                 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,_
                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,_
                 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,_
                 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,_
                 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,_
                 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3_
            }, {_
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,_
                 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,_
                 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,_
                 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,_
                 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,_
                 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,_
                 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,_
                 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7_
            }, {_
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,_
                 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,_
                 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,_
                 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8,_
                 8, 8, 8, 8, 8, 9, 9, 9,10,10,10,10,10,10,10,10,_
                10,11,11,11,12,12,12,12,12,12,12,12,12,13,13,13,_
                14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,_
                15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15_
            }, {_
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,_
                 0, 0, 0, 1, 1, 2, 2, 3, 4, 4, 4, 4, 4, 4, 4, 5,_
                 5, 6, 6, 7, 8, 8, 8, 8, 8, 8, 8, 9, 9,10,10,11,_
                12,12,12,12,12,12,12,13,13,14,14,15,16,16,16,16,_
                16,16,16,17,17,18,18,19,20,20,20,20,20,20,20,21,_
                21,22,22,23,24,24,24,24,24,24,24,25,25,26,26,27,_
                28,28,28,28,28,28,28,29,29,30,30,31,31,31,31,31,_
                31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31_
            }}
dim shared as single detune_table(3,127) = {_
            { 0 },_
            {_
                0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,_
                0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,_
                0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,_
                0.053, 0.053, 0.053, 0.053, 0.053, 0.053, 0.053, 0.053,_
                0.053, 0.053, 0.053, 0.053, 0.053, 0.053, 0.053, 0.053,_
                0.053, 0.053, 0.053, 0.053, 0.053, 0.053, 0.053, 0.053,_
                0.106, 0.106, 0.106, 0.106, 0.106, 0.106, 0.106, 0.106,_
                0.106, 0.106, 0.106, 0.106, 0.106, 0.106, 0.106, 0.106,_
                0.106, 0.106, 0.106, 0.159, 0.159, 0.159, 0.159, 0.159,_
                0.212, 0.212, 0.212, 0.212, 0.212, 0.212, 0.212, 0.212,_
                0.212, 0.212, 0.212, 0.264, 0.264, 0.264, 0.264, 0.264,_
                0.264, 0.264, 0.264, 0.317, 0.317, 0.317, 0.317, 0.370,_
                0.423, 0.423, 0.423, 0.423, 0.423, 0.423, 0.423, 0.423,_
                0.423, 0.423, 0.423, 0.423, 0.423, 0.423, 0.423, 0.423,_
                0.423, 0.423, 0.423, 0.423, 0.423, 0.423, 0.423, 0.423,_
                0.423, 0.423, 0.423, 0.423, 0.423, 0.423, 0.423, 0.423_
            }, {_
                0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,_
                0.000, 0.000, 0.000, 0.000, 0.000, 0.053, 0.053, 0.053,_
                0.053, 0.053, 0.053, 0.053, 0.053, 0.053, 0.053, 0.053,_
                0.106, 0.106, 0.106, 0.106, 0.106, 0.106, 0.106, 0.106,_
                0.106, 0.106, 0.106, 0.106, 0.106, 0.106, 0.106, 0.106,_
                0.106, 0.106, 0.106, 0.106 ,0.106, 0.159, 0.159, 0.159,_
                0.212, 0.212, 0.212, 0.212, 0.212, 0.212, 0.212 ,0.212,_
                0.212, 0.212, 0.212, 0.264, 0.264, 0.264, 0.264, 0.264,_
                0.264, 0.264, 0.264, 0.317, 0.317, 0.317, 0.317, 0.370,_
                0.423, 0.423, 0.423, 0.423, 0.423, 0.423, 0.423, 0.423,_
                0.423, 0.476, 0.476, 0.529, 0.582, 0.582, 0.582, 0.582,_
                0.582, 0.582 ,0.582, 0.635, 0.635, 0.688, 0.688, 0.741,_
                0.846, 0.846, 0.846, 0.846, 0.846, 0.846, 0.846 ,0.846,_
                0.846, 0.846, 0.846, 0.846, 0.846, 0.846, 0.846, 0.846,_
                0.846, 0.846, 0.846, 0.846, 0.846, 0.846, 0.846, 0.846_
            }, {_
                0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,_
                0.000, 0.000, 0.000, 0.000, 0.000, 0.106, 0.106, 0.106,_
                0.106, 0.106, 0.106, 0.106, 0.106, 0.106, 0.106, 0.106,_
                0.106, 0.106, 0.106, 0.106, 0.106, 0.106, 0.106, 0.159,_
                0.159, 0.159, 0.159, 0.159, 0.212, 0.212, 0.212, 0.212,_
                0.212, 0.212, 0.212, 0.212, 0.212, 0.212, 0.212, 0.264,_
                0.264, 0.264, 0.264, 0.264, 0.264, 0.264, 0.264, 0.317,_
                0.317, 0.317, 0.317, 0.370, 0.423, 0.423, 0.423, 0.423,_
                0.423, 0.423, 0.423, 0.423, 0.423, 0.476, 0.476, 0.529,_
                0.582, 0.582, 0.582, 0.582, 0.582, 0.582, 0.582, 0.635,_
                0.635, 0.688, 0.688, 0.741, 0.846, 0.846, 0.846, 0.846,_
                0.846, 0.846, 0.846, 0.899, 0.899, 1.005, 1.005, 1.058,_
                1.164, 1.164, 1.164, 1.164, 1.164, 1.164, 1.164, 1.164,_
                1.164, 1.164, 1.164, 1.164, 1.164, 1.164, 1.164, 1.164,_
                1.164, 1.164, 1.164, 1.164, 1.164, 1.164, 1.164, 1.164,_
                1.164, 1.164, 1.164, 1.164, 1.164, 1.164, 1.164, 1.164_
            }}
dim shared as unsigned long ams_table(3) = {_
            0,_
            128 - 128 * 10^(-1.44 / 10),_
            128 - 128 * 10^(-5.9 / 10),_
            128 - 128 * 10^(-11.8 / 10)_
        }

sub fm_operator.set_freq_rate(freq as single, rate as single)
        freq += DT
        freq *= ML
        swg.set_cycle(rate / freq)
        eg.set_rate(rate)
end sub

function fm_operator.get_next() as integer
        return cast(long,swg.get_next()) * eg.get_next() shr 15
end function

function fm_operator.get_next(modulate as integer) as integer
        return cast(long,swg.get_next(modulate)) * eg.get_next() shr 15
end function

function fm_operator.get_next(ams as integer, modulate as integer) as integer
        return (cast(long,swg.get_next(modulate)) * eg.get_next() shr 15) * (ams * ams_factor + ams_bias) shr 15
end function

sub fm_sound_generator.set_rate(rate as single)
        if this.rate <> rate then
            this.rate = rate
            ams_lfo.set_cycle(rate / ams_freq)
            vibrato_lfo.set_cycle(rate / vibrato_freq)
            tremolo_lfo.set_cycle(rate / tremolo_freq)
            dim as single f = freq * freq_mul
            op1.set_freq_rate(f, rate)
            op2.set_freq_rate(f, rate)
            op3.set_freq_rate(f, rate)
            op4.set_freq_rate(f, rate)
        end if
end sub

sub fm_sound_generator.set_frequency_multiplier(value as single)
        freq_mul = value
        dim as single f = freq * freq_mul
        op1.set_freq_rate(f, rate)
        op2.set_freq_rate(f, rate)
        op3.set_freq_rate(f, rate)
        op4.set_freq_rate(f, rate)
end sub

sub fm_sound_generator.set_damper(damper as integer)
        this.damper = damper
        dim as single value = 1.0 - (1.0 - damper / 127.0) * (1.0 - sostenute / 127.0)
        op1.eg.set_hold(value)
        op2.eg.set_hold(value)
        op3.eg.set_hold(value)
        op4.eg.set_hold(value)
end sub

sub fm_sound_generator.set_sostenute(sostenute as integer)
        this.sostenute = sostenute
        dim as single value = 1.0 - (1.0 - damper / 127.0) * (1.0 - sostenute / 127.0)
        op1.eg.set_hold(value)
        op2.eg.set_hold(value)
        op3.eg.set_hold(value)
        op4.eg.set_hold(value)
end sub

sub fm_sound_generator.set_freeze(freeze as integer)
        dim as single value = freeze / 127.0
        op1.eg.set_freeze(value)
        op2.eg.set_freeze(value)
        op3.eg.set_freeze(value)
        op4.eg.set_freeze(value)
end sub

sub fm_sound_generator.set_tremolo(depth as integer, frequency as single)
        tremolo_depth = depth
        tremolo_freq = frequency
        tremolo_lfo.set_cycle(rate / frequency)
end sub

sub fm_sound_generator.set_vibrato(depth as single, frequency as single)
        vibrato_depth = depth * (16384 / 256.0)
        vibrato_freq = frequency
        vibrato_lfo.set_cycle(rate / frequency)
end sub

sub fm_sound_generator.key_off()
        op1.eg.key_off()
        op2.eg.key_off()
        op3.eg.key_off()
        op4.eg.key_off()
end sub

sub fm_sound_generator.sound_off()
        op1.eg.sound_off()
        op2.eg.sound_off()
        op3.eg.sound_off()
        op4.eg.sound_off()
end sub

function fm_sound_generator.is_finished() as integer
        select case ALG
        case 0 to 3
            return op4.eg.state=FINISHED
        case 4
            return op2.eg.state=FINISHED andalso op4.eg.state=FINISHED
        case 5,6
            return op2.eg.state=FINISHED andalso op3.eg.state=FINISHED andalso op4.eg.state=FINISHED
        case 7
            return op1.eg.state=FINISHED andalso op2.eg.state=FINISHED andalso op3.eg.state=FINISHED andalso op4.eg.state=FINISHED
        case else
            return -1
        end select
end function

function fm_sound_generator.get_next() as integer
        if vibrato_depth<>0 then
            dim as integer x = cast(long,vibrato_lfo.get_next()) * vibrato_depth shr 15
            dim as long modulation = vibrato_table(x+16384/2)
            op1.swg.add_modulation(modulation)
            op2.swg.add_modulation(modulation)
            op3.swg.add_modulation(modulation)
            op4.swg.add_modulation(modulation)
        end if
        dim as integer feedback = (this.feedback shl 1) shr FB
        dim as integer ret
        if ams_enable then
            dim as integer ams = ams_lfo.get_next() shr 7
            select case ALG
            case 0
                this.feedback = op1.get_next(ams, feedback)
                ret = op4.get_next(ams, op3.get_next(ams, op2.get_next(ams, this.feedback)))
            case 1
                this.feedback = op1.get_next(ams, feedback)
                ret = op4.get_next(ams, op3.get_next(ams, op2.get_next(ams, 0) + this.feedback))
            case 2
                this.feedback = op1.get_next(ams, feedback)
                ret = op4.get_next(ams, op3.get_next(ams, op2.get_next(ams, 0)) + this.feedback)
            case 3
                this.feedback = op1.get_next(ams, feedback)
                ret = op4.get_next(ams, op3.get_next(ams, 0) + op2.get_next(ams, this.feedback))
            case 4
                this.feedback = op1.get_next(ams, feedback)
                ret = op4.get_next(ams, op3.get_next(ams, 0)) + op2.get_next(ams, this.feedback)
            case 5
                feedback = op1.get_next(ams, feedback)
                this.feedback = feedback
                ret = op4.get_next(ams, feedback) + op3.get_next(ams, feedback) + op2.get_next(ams, feedback)
            case 6:
                this.feedback = op1.get_next(ams, feedback)
                ret = op4.get_next(ams, 0) + op3.get_next(ams, 0) + op2.get_next(ams, this.feedback)
            case 7
                this.feedback = op1.get_next(ams, feedback)
                ret = op4.get_next(ams, 0) + op3.get_next(ams, 0) + op2.get_next(ams, 0) + this.feedback
            case else
                return 0
            end select
        else
            select case ALG
            case 0
                this.feedback = op1.get_next(feedback)
                ret = op4.get_next(op3.get_next(op2.get_next(this.feedback)))
            case 1
                this.feedback = op1.get_next(feedback)
                ret = op4.get_next(op3.get_next(op2.get_next() + this.feedback))
            case 2
                this.feedback = op1.get_next(feedback)
                ret = op4.get_next(op3.get_next(op2.get_next()) + this.feedback)
            case 3:
                this.feedback = op1.get_next(feedback)
                ret = op4.get_next(op3.get_next() + op2.get_next(this.feedback))
            case 4
                this.feedback = op1.get_next(feedback)
                ret = op4.get_next(op3.get_next()) + op2.get_next(this.feedback)
            case 5
                feedback = op1.get_next(feedback)
                this.feedback = feedback
                ret = op4.get_next(feedback) + op3.get_next(feedback) + op2.get_next(feedback)
            case 6
                this.feedback = op1.get_next(feedback)
                ret = op4.get_next() + op3.get_next() + op2.get_next(this.feedback)
            case 7
                this.feedback = op1.get_next(feedback)
                ret = op4.get_next() + op3.get_next() + op2.get_next() + this.feedback
            case else
                return 0
            end select
        end if
        if tremolo_depth then
            dim as long x = 4096 - (((cast(long,tremolo_lfo.get_next()) + 32768) * tremolo_depth) shr 11)
            ret = ret * x shr 12
        end if
        return ret
end function

function fm_note.synthesize(buf as long ptr, samples as uinteger, rate as single, _left as long, _right as long) as integer
        _left = (_left * velocity) shr 7
        _right = (_right * velocity) shr 7
        fm.set_rate(rate)
        for i as uinteger = 0 to samples
            dim as long sample = fm.get_next()
            buf[i * 2 + 0] += (sample * _left) shr 14
            buf[i * 2 + 1] += (sample * _right) shr 14
        next
        return not fm.is_finished()
end function

sub fm_note_factory.clear_
        static as FMPARAMETER param = (_
            7, 0, 0,_    ' ALG FB LFO
            _'AR DR SR RR SL  TL KS ML DT AMS
            ( 31, 0, 0,15, 0,  0, 0, 0, 0, 0 ),_
            (  0, 0, 0,15, 0,127, 0, 0, 0, 0 ),_
            (  0, 0, 0,15, 0,127, 0, 0, 0, 0 ),_
            (  0, 0, 0,15, 0,127, 0, 0, 0, 0 ))
        erase drums
        erase programs
        programs(128) = @param
end sub

function fm_note_factory.note_on(program as long, note as integer, velocity as integer, frequency_multiplier as single) as fm_note ptr
        dim as integer drum = (program shr 14) = 120
   dim as fm_note ptr new_note= new fm_note

        dim as integer feedbacks(7) = {31, 6, 5, 4, 3, 2, 1, 0}
        dim as single _ams_table(7) = {3.98, 5.56, 6.02, 6.37, 6.88, 9.63, 48.1, 72.2}

        if drum then
            dim as DRUMPARAMETER ptr p=drums(note)
            new_note->assign=p->assign
            new_note->panpot=p->panpot
            new_note->velocity=velocity
            new_note->fm.freq_mul=1
            new_note->fm.freq=440 * 2.0^ ((p->key - 69) / 12.0)

            new_note->fm.tremolo_freq=1
            new_note->fm.vibrato_freq=1
            new_note->fm.ALG=p->ALG
            new_note->fm.FB = feedbacks(p->FB)
            new_note->fm.ams_freq = _ams_table(p->LFO)
            new_note->fm.ams_enable = (p->op1.AMS + p->op2.AMS + p->op3.AMS + p->op4.AMS) <> 0

            if p->op1.DT >= 4 then
                new_note->fm.OP1.DT = -detune_table(p->op1.DT - 4,p->key)
            else
                new_note->fm.OP1.DT = detune_table(p->op1.DT,p->key)
            end if
            if p->op1.ML = 0 then
                new_note->fm.OP1.ML = 0.5
            else
                new_note->fm.OP1.ML = p->op1.ML
            end if
            new_note->fm.OP1.ams_factor = ams_table(p->OP1.AMS) / 2
            new_note->fm.OP1.ams_bias = 32768 - new_note->fm.OP1.ams_factor * 256

            new_note->fm.OP1.eg.state=ATTACK
            new_note->fm.OP1.eg.rate=1
            new_note->fm.OP1.eg.AR=p->OP1.AR * 2 + keyscale_table(p->OP1.KS,p->key)
            new_note->fm.OP1.eg.DR=p->OP1.DR * 2 + keyscale_table(p->OP1.KS,p->key)
            new_note->fm.OP1.eg.SR=p->OP1.SR * 2 + keyscale_table(p->OP1.KS,p->key)
            new_note->fm.OP1.eg.RR=p->OP1.RR * 4 + keyscale_table(p->OP1.KS,p->key) + 2
            new_note->fm.OP1.eg.TL=p->OP1.TL
            new_note->fm.OP1.eg.fTL = envelope_table.TL(p->OP1.TL)

            if new_note->fm.OP1.eg.AR > 63 then new_note->fm.OP1.eg.AR = 63
            if new_note->fm.OP1.eg.DR > 63 then new_note->fm.OP1.eg.DR = 63
            if new_note->fm.OP1.eg.SR > 63 then new_note->fm.OP1.eg.SR = 63
            if new_note->fm.OP1.eg.RR > 63 then new_note->fm.OP1.eg.RR = 63

            new_note->fm.OP1.eg.fSL = envelope_table.SL(p->OP1.SL,p->OP1.TL)
            new_note->fm.OP1.eg.fSS = envelope_table.SL(p->OP1.SL,p->OP1.TL)


            if p->op2.DT >= 4 then
                new_note->fm.OP2.DT = -detune_table(p->op2.DT - 4,p->key)
            else
                new_note->fm.OP2.DT = detune_table(p->op2.DT,p->key)
            end if
            if p->op2.ML = 0 then
                new_note->fm.OP2.ML = 0.5
            else
                new_note->fm.OP2.ML = p->op2.ML
            end if
            new_note->fm.OP2.ams_factor = ams_table(p->OP2.AMS) / 2
            new_note->fm.OP2.ams_bias = 32768 - new_note->fm.OP2.ams_factor * 256

            new_note->fm.OP2.eg.state=ATTACK
            new_note->fm.OP2.eg.rate=1
            new_note->fm.OP2.eg.AR=p->OP2.AR * 2 + keyscale_table(p->OP2.KS,p->key)
            new_note->fm.OP2.eg.DR=p->OP2.DR * 2 + keyscale_table(p->OP2.KS,p->key)
            new_note->fm.OP2.eg.SR=p->OP2.SR * 2 + keyscale_table(p->OP2.KS,p->key)
            new_note->fm.OP2.eg.RR=p->OP2.RR * 4 + keyscale_table(p->OP2.KS,p->key) + 2
            new_note->fm.OP2.eg.TL=p->OP2.TL
            new_note->fm.OP2.eg.fTL = envelope_table.TL(p->OP2.TL)

            if new_note->fm.OP2.eg.AR > 63 then new_note->fm.OP2.eg.AR = 63
            if new_note->fm.OP2.eg.DR > 63 then new_note->fm.OP2.eg.DR = 63
            if new_note->fm.OP2.eg.SR > 63 then new_note->fm.OP2.eg.SR = 63
            if new_note->fm.OP2.eg.RR > 63 then new_note->fm.OP2.eg.RR = 63

            new_note->fm.OP2.eg.fSL = envelope_table.SL(p->OP2.SL,p->OP2.TL)
            new_note->fm.OP2.eg.fSS = envelope_table.SL(p->OP2.SL,p->OP2.TL)


            if p->op3.DT >= 4 then
                new_note->fm.OP3.DT = -detune_table(p->op3.DT - 4,p->key)
            else
                new_note->fm.OP3.DT = detune_table(p->op3.DT,p->key)
            end if
            if p->op3.ML = 0 then
                new_note->fm.OP3.ML = 0.5
            else
                new_note->fm.OP3.ML = p->op3.ML
            end if
            new_note->fm.OP3.ams_factor = ams_table(p->OP3.AMS) / 2
            new_note->fm.OP3.ams_bias = 32768 - new_note->fm.OP3.ams_factor * 256

            new_note->fm.OP3.eg.state=ATTACK
            new_note->fm.OP3.eg.rate=1
            new_note->fm.OP3.eg.AR=p->OP3.AR * 2 + keyscale_table(p->OP3.KS,p->key)
            new_note->fm.OP3.eg.DR=p->OP3.DR * 2 + keyscale_table(p->OP3.KS,p->key)
            new_note->fm.OP3.eg.SR=p->OP3.SR * 2 + keyscale_table(p->OP3.KS,p->key)
            new_note->fm.OP3.eg.RR=p->OP3.RR * 4 + keyscale_table(p->OP3.KS,p->key) + 2
            new_note->fm.OP3.eg.TL=p->OP3.TL
            new_note->fm.OP3.eg.fTL = envelope_table.TL(p->OP3.TL)

            if new_note->fm.OP3.eg.AR > 63 then new_note->fm.OP3.eg.AR = 63
            if new_note->fm.OP3.eg.DR > 63 then new_note->fm.OP3.eg.DR = 63
            if new_note->fm.OP3.eg.SR > 63 then new_note->fm.OP3.eg.SR = 63
            if new_note->fm.OP3.eg.RR > 63 then new_note->fm.OP3.eg.RR = 63

            new_note->fm.OP3.eg.fSL = envelope_table.SL(p->OP3.SL,p->OP3.TL)
            new_note->fm.OP3.eg.fSS = envelope_table.SL(p->OP3.SL,p->OP3.TL)


            if p->op4.DT >= 4 then
                new_note->fm.OP4.DT = -detune_table(p->op4.DT - 4,p->key)
            else
                new_note->fm.OP4.DT = detune_table(p->op4.DT,p->key)
            end if
            if p->op4.ML = 0 then
                new_note->fm.OP4.ML = 0.5
            else
                new_note->fm.OP4.ML = p->op4.ML
            end if
            new_note->fm.OP4.ams_factor = ams_table(p->OP4.AMS) / 2
            new_note->fm.OP4.ams_bias = 32768 - new_note->fm.OP4.ams_factor * 256

            new_note->fm.OP4.eg.state=ATTACK
            new_note->fm.OP4.eg.rate=1
            new_note->fm.OP4.eg.AR=p->OP4.AR * 2 + keyscale_table(p->OP4.KS,p->key)
            new_note->fm.OP4.eg.DR=p->OP4.DR * 2 + keyscale_table(p->OP4.KS,p->key)
            new_note->fm.OP4.eg.SR=p->OP4.SR * 2 + keyscale_table(p->OP4.KS,p->key)
            new_note->fm.OP4.eg.RR=p->OP4.RR * 4 + keyscale_table(p->OP4.KS,p->key) + 2
            new_note->fm.OP4.eg.TL=p->OP4.TL
            new_note->fm.OP4.eg.fTL = envelope_table.TL(p->OP4.TL)

            if new_note->fm.OP4.eg.AR > 63 then new_note->fm.OP4.eg.AR = 63
            if new_note->fm.OP4.eg.DR > 63 then new_note->fm.OP4.eg.DR = 63
            if new_note->fm.OP4.eg.SR > 63 then new_note->fm.OP4.eg.SR = 63
            if new_note->fm.OP4.eg.RR > 63 then new_note->fm.OP4.eg.RR = 63

            new_note->fm.OP4.eg.fSL = envelope_table.SL(p->OP4.SL,p->OP4.TL)
            new_note->fm.OP4.eg.fSS = envelope_table.SL(p->OP4.SL,p->OP4.TL)

            return new_note
        else
            dim as FMPARAMETER ptr p=programs(program)
            new_note->assign=0
            new_note->panpot=8192
            new_note->velocity=velocity
            new_note->fm.freq_mul=frequency_multiplier
            new_note->fm.freq=440 * 2.0^ ((note - 69) / 12.0)

            new_note->fm.tremolo_freq=1
            new_note->fm.vibrato_freq=1
            new_note->fm.ALG=p->ALG
            new_note->fm.FB = feedbacks(p->FB)
            new_note->fm.ams_freq = _ams_table(p->LFO)
            new_note->fm.ams_enable = (p->op1.AMS + p->op2.AMS + p->op3.AMS + p->op4.AMS) <> 0

            if p->op1.DT >= 4 then
                new_note->fm.OP1.DT = -detune_table(p->op1.DT - 4,note)
            else
                new_note->fm.OP1.DT = detune_table(p->op1.DT,note)
            end if
            if p->op1.ML = 0 then
                new_note->fm.OP1.ML = 0.5
            else
                new_note->fm.OP1.ML = p->op1.ML
            end if
            new_note->fm.OP1.ams_factor = ams_table(p->OP1.AMS) / 2
            new_note->fm.OP1.ams_bias = 32768 - new_note->fm.OP1.ams_factor * 256

            new_note->fm.OP1.eg.state=ATTACK
            new_note->fm.OP1.eg.rate=1
            new_note->fm.OP1.eg.AR=p->OP1.AR * 2 + keyscale_table(p->OP1.KS,note)
            new_note->fm.OP1.eg.DR=p->OP1.DR * 2 + keyscale_table(p->OP1.KS,note)
            new_note->fm.OP1.eg.SR=p->OP1.SR * 2 + keyscale_table(p->OP1.KS,note)
            new_note->fm.OP1.eg.RR=p->OP1.RR * 4 + keyscale_table(p->OP1.KS,note) + 2
            new_note->fm.OP1.eg.TL=p->OP1.TL
            new_note->fm.OP1.eg.fTL = envelope_table.TL(p->OP1.TL)

            if new_note->fm.OP1.eg.AR > 63 then new_note->fm.OP1.eg.AR = 63
            if new_note->fm.OP1.eg.DR > 63 then new_note->fm.OP1.eg.DR = 63
            if new_note->fm.OP1.eg.SR > 63 then new_note->fm.OP1.eg.SR = 63
            if new_note->fm.OP1.eg.RR > 63 then new_note->fm.OP1.eg.RR = 63

            new_note->fm.OP1.eg.fSL = envelope_table.SL(p->OP1.SL,p->OP1.TL)
            new_note->fm.OP1.eg.fSS = envelope_table.SL(p->OP1.SL,p->OP1.TL)


            if p->op2.DT >= 4 then
                new_note->fm.OP2.DT = -detune_table(p->op2.DT - 4,note)
            else
                new_note->fm.OP2.DT = detune_table(p->op2.DT,note)
            end if
            if p->op2.ML = 0 then
                new_note->fm.OP2.ML = 0.5
            else
                new_note->fm.OP2.ML = p->op2.ML
            end if
            new_note->fm.OP2.ams_factor = ams_table(p->OP2.AMS) / 2
            new_note->fm.OP2.ams_bias = 32768 - new_note->fm.OP2.ams_factor * 256

            new_note->fm.OP2.eg.state=ATTACK
            new_note->fm.OP2.eg.rate=1
            new_note->fm.OP2.eg.AR=p->OP2.AR * 2 + keyscale_table(p->OP2.KS,note)
            new_note->fm.OP2.eg.DR=p->OP2.DR * 2 + keyscale_table(p->OP2.KS,note)
            new_note->fm.OP2.eg.SR=p->OP2.SR * 2 + keyscale_table(p->OP2.KS,note)
            new_note->fm.OP2.eg.RR=p->OP2.RR * 4 + keyscale_table(p->OP2.KS,note) + 2
            new_note->fm.OP2.eg.TL=p->OP2.TL
            new_note->fm.OP2.eg.fTL = envelope_table.TL(p->OP2.TL)

            if new_note->fm.OP2.eg.AR > 63 then new_note->fm.OP2.eg.AR = 63
            if new_note->fm.OP2.eg.DR > 63 then new_note->fm.OP2.eg.DR = 63
            if new_note->fm.OP2.eg.SR > 63 then new_note->fm.OP2.eg.SR = 63
            if new_note->fm.OP2.eg.RR > 63 then new_note->fm.OP2.eg.RR = 63

            new_note->fm.OP2.eg.fSL = envelope_table.SL(p->OP2.SL,p->OP2.TL)
            new_note->fm.OP2.eg.fSS = envelope_table.SL(p->OP2.SL,p->OP2.TL)


            if p->op3.DT >= 4 then
                new_note->fm.OP3.DT = -detune_table(p->op3.DT - 4,note)
            else
                new_note->fm.OP3.DT = detune_table(p->op3.DT,note)
            end if
            if p->op3.ML = 0 then
                new_note->fm.OP3.ML = 0.5
            else
                new_note->fm.OP3.ML = p->op3.ML
            end if
            new_note->fm.OP3.ams_factor = ams_table(p->OP3.AMS) / 2
            new_note->fm.OP3.ams_bias = 32768 - new_note->fm.OP3.ams_factor * 256

            new_note->fm.OP3.eg.state=ATTACK
            new_note->fm.OP3.eg.rate=1
            new_note->fm.OP3.eg.AR=p->OP3.AR * 2 + keyscale_table(p->OP3.KS,note)
            new_note->fm.OP3.eg.DR=p->OP3.DR * 2 + keyscale_table(p->OP3.KS,note)
            new_note->fm.OP3.eg.SR=p->OP3.SR * 2 + keyscale_table(p->OP3.KS,note)
            new_note->fm.OP3.eg.RR=p->OP3.RR * 4 + keyscale_table(p->OP3.KS,note) + 2
            new_note->fm.OP3.eg.TL=p->OP3.TL
            new_note->fm.OP3.eg.fTL = envelope_table.TL(p->OP3.TL)

            if new_note->fm.OP3.eg.AR > 63 then new_note->fm.OP3.eg.AR = 63
            if new_note->fm.OP3.eg.DR > 63 then new_note->fm.OP3.eg.DR = 63
            if new_note->fm.OP3.eg.SR > 63 then new_note->fm.OP3.eg.SR = 63
            if new_note->fm.OP3.eg.RR > 63 then new_note->fm.OP3.eg.RR = 63

            new_note->fm.OP3.eg.fSL = envelope_table.SL(p->OP3.SL,p->OP3.TL)
            new_note->fm.OP3.eg.fSS = envelope_table.SL(p->OP3.SL,p->OP3.TL)


            if p->op4.DT >= 4 then
                new_note->fm.OP4.DT = -detune_table(p->op4.DT - 4,note)
            else
                new_note->fm.OP4.DT = detune_table(p->op4.DT,note)
            end if
            if p->op4.ML = 0 then
                new_note->fm.OP4.ML = 0.5
            else
                new_note->fm.OP4.ML = p->op4.ML
            end if
            new_note->fm.OP4.ams_factor = ams_table(p->OP4.AMS) / 2
            new_note->fm.OP4.ams_bias = 32768 - new_note->fm.OP4.ams_factor * 256

            new_note->fm.OP4.eg.state=ATTACK
            new_note->fm.OP4.eg.rate=1
            new_note->fm.OP4.eg.AR=p->OP4.AR * 2 + keyscale_table(p->OP4.KS,note)
            new_note->fm.OP4.eg.DR=p->OP4.DR * 2 + keyscale_table(p->OP4.KS,note)
            new_note->fm.OP4.eg.SR=p->OP4.SR * 2 + keyscale_table(p->OP4.KS,note)
            new_note->fm.OP4.eg.RR=p->OP4.RR * 4 + keyscale_table(p->OP4.KS,note) + 2
            new_note->fm.OP4.eg.TL=p->OP4.TL
            new_note->fm.OP4.eg.fTL = envelope_table.TL(p->OP4.TL)

            if new_note->fm.OP4.eg.AR > 63 then new_note->fm.OP4.eg.AR = 63
            if new_note->fm.OP4.eg.DR > 63 then new_note->fm.OP4.eg.DR = 63
            if new_note->fm.OP4.eg.SR > 63 then new_note->fm.OP4.eg.SR = 63
            if new_note->fm.OP4.eg.RR > 63 then new_note->fm.OP4.eg.RR = 63

            new_note->fm.OP4.eg.fSL = envelope_table.SL(p->OP4.SL,p->OP4.TL)
            new_note->fm.OP4.eg.fSS = envelope_table.SL(p->OP4.SL,p->OP4.TL)

            return new_note
        end if
end function
Last edited by angros47 on Dec 20, 2013 10:41, edited 1 time in total.
angros47
Posts: 1421
Joined: Jun 21, 2005 19:04

Re: Cross-platform MIDI in pure FreeBasic!

Postby angros47 » Dec 12, 2013 21:55

Here are the included files:

instruments.bi

Code: Select all

dim shared as FMPARAMETER programs(128) = {_
( 4, 3, 0,_
  ( 26, 10, 1, 0, 0, 2, 0, 1, 3, 0),_
  ( 26, 10, 2, 7, 2, 0, 0, 2, 3, 0),_
  ( 26, 10, 2, 0, 0, 4, 0, 1, 7, 0),_
  ( 18, 6, 1, 6, 4, 2, 1, 1, 7, 0)_
),_
( 4, 5, 0,_
  ( 26, 10, 1, 0, 0, 5, 0, 2, 3, 0),_
  ( 26, 10, 3, 7, 1, 0, 0, 2, 3, 0),_
  ( 26, 10, 2, 0, 0, 20, 0, 1, 7, 0),_
  ( 18, 6, 2, 6, 4, 2, 0, 1, 7, 0)_
),_
( 4, 5, 0,_
  ( 26, 10, 1, 0, 0, 2, 0, 2, 3, 0),_
  ( 26, 10, 2, 7, 2, 0, 0, 1, 3, 0),_
  ( 26, 10, 2, 0, 0, 4, 0, 1, 7, 0),_
  ( 18, 6, 1, 6, 4, 2, 1, 1, 7, 0)_
),_
( 5, 7, 0,_
  ( 26, 10, 1, 0, 0, 10, 3, 6, 0, 0),_
  ( 26, 10, 4, 7, 1, 1, 0, 1, 7, 0),_
  ( 15, 20, 5, 8, 1, 2, 1, 2, 0, 0),_
  ( 8, 15, 3, 11, 2, 3, 3, 3, 3, 0)_
),_
( 4, 3, 0,_
  ( 28, 10, 0, 0, 0, 2, 0, 2, 0, 0),_
  ( 31, 16, 0, 12, 1, 0, 0, 1, 0, 0),_
  ( 28, 10, 0, 0, 0, 20, 0, 1, 0, 0),_
  ( 22, 9, 0, 10, 4, 2, 0, 2, 0, 0)_
),_
( 6, 4, 0,_
  ( 31, 12, 0, 0, 0, 0, 0, 1, 3, 0),_
  ( 29, 12, 1, 7, 1, 1, 0, 1, 0, 0),_
  ( 26, 12, 2, 6, 2, 4, 0, 2, 3, 0),_
  ( 26, 12, 2, 6, 2, 5, 0, 0, 7, 0)_
),_
( 2, 4, 0,_
  ( 28, 16, 1, 0, 0, 2, 0, 2, 7, 0),_
  ( 28, 16, 2, 8, 1, 0, 0, 1, 3, 0),_
  ( 28, 14, 2, 8, 0, 4, 0, 3, 3, 0),_
  ( 28, 12, 1, 7, 2, 0, 1, 1, 0, 0)_
),_
( 2, 4, 0,_
  ( 28, 16, 1, 0, 0, 2, 0, 2, 7, 0),_
  ( 28, 16, 2, 7, 1, 4, 0, 1, 3, 0),_
  ( 28, 14, 2, 7, 0, 4, 0, 4, 3, 0),_
  ( 28, 14, 1, 7, 2, 0, 1, 1, 0, 0)_
),_
( 7, 6, 0,_
  ( 31, 18, 9, 6, 1, 1, 0, 4, 0, 0),_
  ( 28, 14, 8, 5, 3, 2, 0, 2, 3, 0),_
  ( 28, 14, 9, 6, 1, 0, 0, 1, 0, 0),_
  ( 28, 14, 10, 6, 2, 2, 0, 0, 7, 0)_
),_
( 7, 6, 0,_
  ( 31, 26, 21, 10, 2, 2, 0, 7, 0, 0),_
  ( 20, 0, 11, 5, 0, 7, 0, 4, 1, 0),_
  ( 31, 0, 11, 5, 0, 3, 0, 4, 0, 0),_
  ( 31, 28, 15, 7, 3, 0, 0, 2, 0, 0)_
),_
( 6, 2, 0,_
  ( 31, 0, 0, 0, 0, 2, 0, 4, 0, 0),_
  ( 31, 0, 13, 6, 0, 2, 0, 2, 0, 0),_
  ( 31, 0, 25, 12, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 13, 6, 0, 0, 3, 4, 0, 0)_
),_
( 6, 4, 0,_
  ( 31, 16, 0, 0, 2, 1, 0, 7, 7, 0),_
  ( 31, 0, 10, 7, 0, 4, 0, 1, 3, 0),_
  ( 24, 10, 9, 7, 1, 2, 1, 1, 7, 0),_
  ( 31, 24, 13, 9, 4, 0, 0, 1, 0, 0)_
),_
( 7, 1, 0,_
  ( 27, 20, 25, 12, 1, 2, 0, 1, 0, 0),_
  ( 16, 0, 13, 6, 0, 12, 0, 4, 0, 0),_
  ( 16, 0, 15, 7, 0, 2, 0, 1, 0, 0),_
  ( 27, 0, 19, 9, 0, 4, 0, 4, 0, 0)_
),_
( 7, 0, 0,_
  ( 31, 0, 11, 5, 0, 0, 2, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 4, 1, 3, 0, 0),_
  ( 31, 0, 19, 9, 0, 8, 0, 6, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 6, 3, 0,_
  ( 31, 0, 0, 0, 0, 2, 0, 5, 0, 0),_
  ( 31, 16, 11, 5, 2, 0, 0, 1, 3, 0),_
  ( 24, 0, 13, 6, 0, 6, 0, 2, 7, 0),_
  ( 31, 0, 19, 9, 0, 1, 0, 3, 0, 0)_
),_
( 4, 4, 0,_
  ( 31, 0, 0, 0, 0, 7, 0, 3, 0, 0),_
  ( 28, 24, 9, 6, 1, 1, 1, 1, 7, 0),_
  ( 28, 0, 9, 6, 0, 0, 0, 7, 3, 0),_
  ( 28, 24, 9, 6, 2, 3, 1, 1, 3, 0)_
),_
( 7, 5, 0,_
  ( 28, 0, 0, 12, 0, 4, 0, 0, 0, 0),_
  ( 28, 0, 0, 12, 0, 6, 0, 4, 0, 0),_
  ( 28, 0, 0, 12, 0, 4, 0, 2, 0, 0),_
  ( 28, 0, 0, 12, 0, 3, 0, 1, 0, 0)_
),_
( 7, 3, 0,_
  ( 31, 22, 0, 12, 10, 0, 0, 4, 0, 0),_
  ( 31, 20, 0, 12, 2, 0, 0, 2, 0, 0),_
  ( 31, 18, 0, 12, 1, 0, 0, 1, 0, 0),_
  ( 31, 18, 0, 12, 1, 0, 0, 0, 0, 0)_
),_
( 7, 5, 0,_
  ( 28, 0, 0, 12, 0, 4, 0, 0, 0, 3),_
  ( 28, 0, 0, 12, 0, 6, 0, 4, 0, 0),_
  ( 28, 0, 0, 12, 0, 4, 0, 2, 0, 0),_
  ( 28, 0, 0, 12, 0, 3, 0, 1, 0, 2)_
),_
( 6, 5, 0,_
  ( 18, 0, 0, 9, 0, 2, 0, 6, 0, 0),_
  ( 20, 0, 0, 9, 0, 2, 0, 2, 0, 0),_
  ( 18, 0, 0, 10, 0, 3, 0, 4, 3, 0),_
  ( 28, 0, 0, 12, 0, 5, 0, 1, 7, 0)_
),_
( 6, 2, 0,_
  ( 14, 0, 0, 10, 0, 0, 0, 6, 0, 0),_
  ( 20, 0, 0, 12, 0, 2, 1, 2, 0, 0),_
  ( 14, 0, 0, 8, 0, 1, 0, 1, 0, 0),_
  ( 17, 0, 0, 8, 0, 8, 1, 0, 0, 0)_
),_
( 3, 3, 0,_
  ( 16, 0, 0, 0, 0, 4, 0, 4, 0, 0),_
  ( 12, 3, 0, 0, 4, 6, 0, 1, 0, 0),_
  ( 14, 7, 0, 8, 4, 3, 0, 3, 0, 0),_
  ( 22, 0, 0, 8, 0, 0, 0, 1, 0, 0)_
),_
( 4, 5, 0,_
  ( 16, 0, 1, 11, 0, 3, 0, 5, 3, 0),_
  ( 20, 0, 3, 9, 0, 2, 0, 2, 3, 0),_
  ( 18, 0, 1, 11, 0, 0, 0, 4, 7, 0),_
  ( 24, 0, 2, 10, 0, 2, 0, 1, 7, 0)_
),_
( 3, 3, 0,_
  ( 20, 0, 0, 0, 0, 2, 0, 4, 0, 0),_
  ( 16, 3, 0, 0, 4, 4, 0, 1, 0, 0),_
  ( 18, 7, 0, 8, 4, 3, 0, 3, 0, 0),_
  ( 24, 0, 0, 9, 0, 0, 0, 1, 0, 0)_
),_
( 0, 0, 0,_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 0, 0, 2, 0, 0),_
  ( 31, 0, 4, 10, 0, 2, 0, 1, 0, 0),_
  ( 29, 14, 8, 9, 2, 0, 0, 1, 0, 0)_
),_
( 1, 4, 0,_
  ( 31, 0, 0, 0, 0, 1, 0, 2, 0, 0),_
  ( 31, 0, 0, 0, 0, 2, 0, 1, 0, 0),_
  ( 31, 0, 4, 10, 0, 2, 0, 1, 0, 0),_
  ( 31, 20, 8, 9, 2, 0, 0, 1, 0, 0)_
),_
( 1, 4, 0,_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 4, 0, 3, 0, 0),_
  ( 31, 0, 4, 10, 0, 4, 0, 2, 0, 0),_
  ( 28, 12, 8, 9, 1, 3, 0, 1, 0, 0)_
),_
( 0, 0, 0,_
  ( 20, 0, 2, 9, 0, 10, 0, 12, 0, 0),_
  ( 26, 0, 2, 10, 0, 2, 0, 4, 0, 0),_
  ( 28, 0, 4, 10, 0, 2, 0, 1, 0, 0),_
  ( 31, 14, 8, 9, 2, 4, 0, 1, 0, 0)_
),_
( 0, 0, 0,_
  ( 20, 0, 2, 15, 0, 10, 0, 4, 0, 0),_
  ( 26, 0, 2, 15, 0, 4, 0, 2, 0, 0),_
  ( 28, 0, 6, 15, 0, 8, 0, 1, 0, 0),_
  ( 31, 16, 10, 15, 2, 5, 0, 1, 0, 0)_
),_
( 1, 0, 0,_
  ( 16, 0, 0, 12, 0, 4, 0, 4, 0, 0),_
  ( 18, 0, 0, 12, 0, 2, 0, 3, 0, 0),_
  ( 20, 0, 0, 12, 0, 1, 0, 1, 0, 0),_
  ( 29, 4, 2, 12, 1, 2, 0, 1, 0, 0)_
),_
( 5, 0, 0,_
  ( 20, 0, 1, 9, 0, 4, 0, 5, 0, 0),_
  ( 28, 14, 1, 9, 1, 4, 0, 5, 7, 0),_
  ( 28, 14, 1, 9, 1, 4, 0, 2, 0, 0),_
  ( 28, 14, 1, 9, 1, 4, 0, 1, 3, 0)_
),_
( 4, 3, 0,_
  ( 31, 0, 0, 9, 0, 2, 0, 8, 0, 0),_
  ( 31, 12, 2, 9, 2, 4, 0, 2, 0, 0),_
  ( 31, 18, 0, 9, 5, 1, 0, 10, 0, 0),_
  ( 31, 18, 0, 9, 3, 2, 0, 1, 0, 0)_
),_
( 4, 5, 0,_
  ( 24, 0, 0, 0, 0, 4, 2, 0, 0, 0),_
  ( 24, 18, 4, 8, 1, 0, 2, 2, 0, 0),_
  ( 18, 18, 3, 7, 1, 6, 0, 1, 0, 0),_
  ( 22, 18, 3, 7, 1, 2, 0, 2, 0, 0)_
),_
( 2, 3, 0,_
  ( 28, 10, 0, 15, 1, 2, 0, 2, 0, 0),_
  ( 26, 22, 0, 6, 1, 1, 0, 2, 0, 0),_
  ( 28, 8, 8, 8, 1, 1, 0, 1, 0, 0),_
  ( 22, 14, 0, 7, 1, 0, 0, 1, 0, 0)_
),_
( 2, 3, 0,_
  ( 28, 10, 5, 15, 1, 2, 0, 2, 0, 0),_
  ( 26, 22, 10, 6, 1, 1, 0, 2, 0, 0),_
  ( 28, 8, 8, 8, 1, 1, 0, 1, 0, 0),_
  ( 28, 14, 6, 7, 1, 0, 0, 1, 0, 0)_
),_
( 4, 0, 0,_
  ( 24, 8, 3, 13, 0, 2, 0, 1, 0, 0),_
  ( 28, 9, 1, 13, 2, 0, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 2, 0, 0,_
  ( 28, 10, 5, 15, 1, 2, 0, 2, 0, 0),_
  ( 26, 18, 8, 6, 1, 1, 0, 2, 0, 0),_
  ( 28, 6, 6, 10, 1, 1, 0, 1, 0, 0),_
  ( 28, 4, 6, 10, 1, 2, 0, 1, 0, 0)_
),_
( 2, 0, 0,_
  ( 28, 10, 2, 15, 1, 2, 0, 2, 0, 0),_
  ( 26, 18, 0, 6, 1, 1, 0, 2, 0, 0),_
  ( 28, 6, 2, 10, 1, 1, 0, 1, 0, 0),_
  ( 28, 4, 4, 10, 1, 2, 0, 1, 0, 0)_
),_
( 2, 4, 0,_
  ( 28, 16, 12, 15, 1, 2, 0, 2, 7, 0),_
  ( 26, 12, 6, 6, 2, 1, 0, 1, 0, 0),_
  ( 28, 13, 11, 8, 1, 1, 0, 2, 3, 0),_
  ( 28, 10, 6, 12, 3, 0, 0, 1, 0, 0)_
),_
( 3, 1, 0,_
  ( 28, 7, 3, 15, 1, 2, 0, 1, 0, 0),_
  ( 28, 10, 2, 6, 1, 1, 0, 1, 0, 0),_
  ( 28, 10, 1, 8, 1, 2, 0, 1, 0, 0),_
  ( 31, 0, 0, 12, 1, 0, 0, 1, 0, 0)_
),_
( 5, 7, 0,_
  ( 20, 0, 0, 6, 0, 11, 0, 1, 0, 0),_
  ( 16, 0, 0, 6, 0, 4, 0, 2, 0, 0),_
  ( 16, 0, 0, 6, 0, 6, 0, 4, 0, 0),_
  ( 16, 0, 0, 6, 0, 10, 0, 8, 0, 0)_
),_
( 3, 7, 0,_
  ( 20, 0, 0, 0, 0, 8, 0, 1, 0, 0),_
  ( 16, 0, 0, 6, 0, 4, 0, 2, 0, 0),_
  ( 16, 0, 0, 6, 0, 8, 0, 3, 0, 0),_
  ( 16, 0, 0, 6, 0, 4, 0, 1, 0, 0)_
),_
( 2, 4, 0,_
  ( 20, 1, 1, 0, 0, 4, 0, 2, 0, 0),_
  ( 20, 2, 2, 0, 0, 0, 0, 1, 0, 0),_
  ( 20, 2, 2, 0, 0, 4, 0, 2, 0, 0),_
  ( 20, 1, 1, 1, 7, 0, 3, 1, 0, 0)_
),_
( 2, 5, 0,_
  ( 31, 1, 1, 0, 0, 4, 0, 3, 0, 0),_
  ( 31, 1, 1, 0, 0, 4, 0, 2, 0, 0),_
  ( 31, 1, 1, 0, 0, 3, 0, 2, 0, 0),_
  ( 20, 1, 1, 7, 0, 4, 1, 1, 0, 0)_
),_
( 3, 4, 1,_
  ( 31, 0, 0, 0, 0, 5, 0, 5, 0, 1),_
  ( 31, 0, 0, 0, 0, 4, 0, 2, 0, 0),_
  ( 20, 10, 0, 0, 0, 6, 0, 5, 0, 0),_
  ( 20, 14, 0, 8, 1, 2, 0, 1, 0, 0)_
),_
( 5, 4, 0,_
  ( 28, 0, 13, 6, 0, 0, 0, 1, 0, 0),_
  ( 28, 0, 13, 6, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 19, 9, 0, 0, 0, 4, 0, 0),_
  ( 31, 0, 17, 8, 0, 0, 0, 2, 0, 0)_
),_
( 6, 2, 0,_
  ( 28, 0, 9, 6, 0, 4, 1, 3, 0, 0),_
  ( 28, 16, 9, 6, 1, 0, 1, 1, 0, 0),_
  ( 28, 16, 9, 6, 1, 0, 1, 2, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 0, 6, 0,_
  ( 31, 0, 13, 6, 0, 0, 2, 3, 0, 0),_
  ( 31, 0, 13, 6, 0, 0, 2, 4, 0, 0),_
  ( 31, 0, 13, 6, 0, 0, 2, 2, 0, 0),_
  ( 31, 0, 13, 6, 0, 0, 2, 1, 0, 0)_
),_
( 3, 4, 0,_
  ( 31, 0, 0, 0, 0, 5, 0, 5, 0, 0),_
  ( 31, 0, 0, 0, 0, 4, 0, 2, 0, 0),_
  ( 24, 10, 0, 0, 0, 6, 0, 5, 0, 0),_
  ( 20, 14, 0, 8, 1, 2, 0, 1, 0, 0)_
),_
( 3, 4, 0,_
  ( 31, 0, 0, 0, 0, 5, 0, 5, 0, 0),_
  ( 31, 0, 0, 0, 0, 4, 0, 2, 0, 0),_
  ( 24, 10, 0, 0, 0, 6, 0, 5, 0, 0),_
  ( 12, 0, 0, 6, 0, 4, 0, 1, 0, 0)_
),_
( 3, 4, 0,_
  ( 14, 0, 0, 0, 0, 1, 0, 5, 3, 0),_
  ( 14, 0, 0, 0, 0, 4, 0, 2, 0, 0),_
  ( 14, 10, 0, 0, 0, 6, 0, 5, 0, 0),_
  ( 14, 14, 0, 8, 1, 2, 0, 1, 0, 0)_
),_
( 3, 4, 0,_
  ( 14, 0, 0, 0, 0, 1, 0, 5, 3, 0),_
  ( 14, 0, 0, 0, 0, 4, 0, 2, 0, 0),_
  ( 14, 10, 0, 0, 0, 6, 0, 5, 0, 0),_
  ( 12, 0, 0, 6, 0, 2, 0, 1, 0, 0)_
),_
( 7, 5, 0,_
  ( 16, 0, 0, 8, 0, 4, 0, 2, 7, 0),_
  ( 16, 0, 0, 8, 0, 0, 0, 1, 7, 0),_
  ( 18, 0, 0, 9, 0, 2, 0, 2, 3, 0),_
  ( 18, 0, 0, 9, 0, 3, 0, 1, 3, 0)_
),_
( 7, 4, 0,_
  ( 24, 0, 0, 8, 0, 0, 0, 1, 3, 0),_
  ( 24, 0, 0, 8, 0, 2, 0, 1, 7, 0),_
  ( 24, 0, 0, 8, 0, 15, 0, 4, 0, 0),_
  ( 24, 0, 0, 8, 0, 18, 0, 0, 0, 0)_
),_
( 7, 3, 0,_
  ( 17, 0, 0, 7, 0, 0, 0, 1, 3, 0),_
  ( 17, 0, 0, 7, 0, 0, 0, 1, 7, 0),_
  ( 17, 0, 0, 7, 0, 8, 0, 2, 0, 0),_
  ( 17, 0, 0, 7, 0, 14, 0, 4, 0, 0)_
),_
( 5, 5, 0,_
  ( 16, 0, 13, 6, 0, 0, 0, 1, 0, 0),_
  ( 18, 0, 13, 6, 0, 0, 0, 0, 0, 0),_
  ( 20, 0, 13, 6, 0, 0, 0, 1, 0, 0),_
  ( 16, 0, 13, 6, 0, 0, 0, 2, 0, 0)_
),_
( 4, 4, 0,_
  ( 22, 0, 0, 0, 0, 1, 0, 1, 0, 0),_
  ( 22, 0, 0, 8, 0, 0, 0, 1, 0, 0),_
  ( 22, 0, 0, 0, 0, 8, 0, 1, 0, 0),_
  ( 22, 0, 0, 8, 0, 0, 0, 1, 0, 0)_
),_
( 4, 4, 0,_
  ( 17, 0, 0, 8, 0, 1, 0, 1, 0, 0),_
  ( 17, 0, 0, 8, 0, 0, 0, 1, 0, 0),_
  ( 20, 0, 0, 8, 1, 4, 0, 1, 0, 0),_
  ( 20, 0, 0, 8, 1, 12, 0, 1, 0, 0)_
),_
( 4, 3, 0,_
  ( 17, 0, 0, 8, 0, 1, 0, 1, 0, 0),_
  ( 17, 0, 0, 8, 0, 0, 0, 1, 0, 0),_
  ( 20, 0, 0, 8, 1, 4, 0, 1, 0, 0),_
  ( 20, 0, 0, 8, 1, 12, 0, 1, 0, 0)_
),_
( 3, 3, 0,_
  ( 31, 0, 0, 0, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 6, 0, 4, 0, 0),_
  ( 18, 0, 0, 9, 0, 0, 0, 1, 0, 0)_
),_
( 4, 2, 0,_
  ( 17, 0, 0, 8, 0, 1, 0, 1, 0, 0),_
  ( 17, 0, 0, 8, 0, 0, 0, 1, 0, 0),_
  ( 20, 0, 0, 8, 1, 4, 0, 1, 0, 0),_
  ( 20, 0, 0, 8, 1, 12, 0, 1, 0, 0)_
),_
( 4, 5, 0,_
  ( 17, 9, 0, 9, 1, 0, 0, 1, 0, 0),_
  ( 17, 0, 0, 9, 0, 0, 0, 1, 0, 0),_
  ( 17, 0, 0, 9, 0, 0, 0, 2, 0, 0),_
  ( 17, 0, 0, 9, 0, 4, 0, 1, 0, 0)_
),_
( 4, 5, 0,_
  ( 17, 0, 0, 9, 0, 0, 0, 1, 0, 0),_
  ( 17, 9, 0, 9, 2, 0, 0, 1, 0, 0),_
  ( 31, 0, 0, 9, 0, 0, 0, 2, 0, 0),_
  ( 17, 0, 0, 9, 0, 4, 0, 3, 0, 0)_
),_
( 4, 5, 0,_
  ( 14, 0, 0, 9, 0, 0, 0, 1, 0, 0),_
  ( 14, 7, 0, 9, 2, 0, 0, 1, 0, 0),_
  ( 31, 0, 0, 9, 0, 0, 0, 2, 0, 0),_
  ( 14, 0, 0, 9, 0, 4, 0, 3, 0, 0)_
),_
( 3, 5, 0,_
  ( 31, 0, 0, 0, 0, 8, 0, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 4, 0, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 4, 0, 1, 0, 0),_
  ( 20, 0, 0, 10, 0, 0, 0, 1, 0, 0)_
),_
( 1, 4, 0,_
  ( 31, 0, 0, 0, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 2, 0, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 6, 0, 1, 0, 0),_
  ( 20, 0, 0, 10, 0, 0, 0, 1, 0, 0)_
),_
( 1, 5, 0,_
  ( 31, 0, 0, 0, 0, 4, 0, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 2, 0, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 2, 0, 1, 0, 0),_
  ( 20, 0, 0, 10, 0, 0, 0, 1, 0, 0)_
),_
( 3, 4, 0,_
  ( 31, 0, 0, 0, 0, 0, 0, 2, 0, 0),_
  ( 31, 0, 0, 0, 0, 4, 0, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 6, 0, 1, 0, 0),_
  ( 24, 0, 0, 10, 0, 0, 0, 1, 0, 0)_
),_
( 5, 5, 0,_
  ( 18, 0, 0, 0, 0, 3, 0, 1, 0, 0),_
  ( 18, 0, 0, 9, 0, 0, 0, 1, 0, 0),_
  ( 18, 0, 0, 9, 0, 4, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 4, 4, 0,_
  ( 20, 0, 0, 9, 0, 1, 0, 1, 0, 0),_
  ( 20, 0, 0, 9, 0, 0, 0, 1, 0, 0),_
  ( 24, 0, 0, 9, 0, 2, 0, 1, 0, 0),_
  ( 24, 0, 0, 9, 0, 4, 0, 1, 0, 0)_
),_
( 3, 2, 0,_
  ( 31, 0, 0, 0, 0, 7, 0, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 2, 0, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 6, 0, 2, 0, 0),_
  ( 22, 0, 0, 10, 0, 0, 0, 1, 0, 0)_
),_
( 4, 5, 0,_
  ( 31, 0, 0, 0, 0, 5, 0, 2, 0, 0),_
  ( 16, 0, 0, 8, 0, 0, 1, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 4, 0, 1, 0, 0),_
  ( 16, 0, 0, 8, 0, 0, 1, 1, 0, 0)_
),_
( 4, 4, 0,_
  ( 16, 0, 0, 9, 0, 12, 0, 2, 0, 0),_
  ( 20, 0, 0, 9, 0, 0, 1, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 12, 0, 2, 0, 0),_
  ( 16, 0, 0, 9, 0, 8, 0, 1, 0, 0)_
),_
( 6, 1, 0,_
  ( 31, 0, 0, 0, 0, 1, 0, 1, 0, 0),_
  ( 18, 0, 0, 9, 0, 0, 0, 1, 0, 0),_
  ( 18, 0, 0, 9, 0, 1, 0, 2, 0, 0),_
  ( 18, 0, 0, 9, 0, 3, 0, 3, 0, 0)_
),_
( 6, 3, 0,_
  ( 31, 0, 0, 0, 0, 8, 0, 2, 0, 0),_
  ( 20, 0, 0, 9, 0, 0, 0, 1, 0, 0),_
  ( 20, 0, 0, 9, 0, 4, 0, 1, 0, 0),_
  ( 28, 18, 0, 9, 1, 2, 0, 1, 0, 0)_
),_
( 4, 4, 0,_
  ( 31, 0, 0, 10, 0, 6, 0, 2, 0, 0),_
  ( 17, 0, 0, 10, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 0, 15, 0, 6, 0, 2, 0, 0),_
  ( 17, 0, 0, 10, 0, 8, 0, 1, 0, 0)_
),_
( 6, 4, 0,_
  ( 13, 0, 0, 9, 0, 8, 0, 2, 3, 0),_
  ( 16, 0, 0, 9, 0, 0, 0, 1, 0, 0),_
  ( 16, 0, 0, 9, 0, 8, 0, 2, 0, 0),_
  ( 16, 0, 0, 9, 0, 16, 0, 4, 0, 0)_
),_
( 4, 4, 2,_
  ( 12, 0, 0, 0, 0, 4, 0, 1, 0, 0),_
  ( 20, 0, 0, 9, 0, 0, 0, 1, 0, 0),_
  ( 12, 0, 0, 0, 0, 10, 0, 2, 0, 2),_
  ( 20, 0, 0, 9, 0, 0, 0, 1, 0, 0)_
),_
( 6, 2, 0,_
  ( 14, 0, 0, 0, 0, 8, 0, 2, 0, 0),_
  ( 18, 0, 0, 9, 0, 0, 0, 1, 0, 0),_
  ( 18, 0, 0, 9, 0, 0, 0, 3, 0, 0),_
  ( 18, 0, 0, 9, 0, 2, 0, 4, 0, 0)_
),_
( 7, 4, 0,_
  ( 17, 0, 0, 9, 0, 4, 0, 1, 0, 0),_
  ( 17, 0, 0, 9, 0, 0, 0, 1, 0, 0),_
  ( 17, 0, 0, 9, 0, 0, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 6, 5, 0,_
  ( 31, 0, 0, 15, 0, 4, 0, 2, 0, 0),_
  ( 31, 0, 0, 15, 0, 1, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 6, 5, 0,_
  ( 31, 0, 0, 15, 0, 4, 0, 1, 0, 0),_
  ( 31, 0, 0, 15, 0, 1, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 4, 2, 0,_
  ( 2, 0, 0, 10, 0, 0, 0, 1, 0, 0),_
  ( 20, 16, 0, 10, 1, 0, 0, 1, 0, 0),_
  ( 20, 0, 0, 10, 0, 1, 0, 2, 0, 0),_
  ( 20, 16, 0, 10, 1, 0, 0, 1, 0, 0)_
),_
( 3, 7, 0,_
  ( 16, 0, 14, 11, 0, 5, 0, 1, 0, 0),_
  ( 31, 0, 0, 0, 0, 0, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 28, 0, 0, 11, 0, 0, 0, 1, 0, 0)_
),_
( 5, 4, 0,_
  ( 16, 16, 1, 9, 1, 0, 0, 4, 0, 0),_
  ( 28, 14, 1, 9, 1, 2, 0, 4, 0, 0),_
  ( 28, 14, 1, 9, 1, 2, 0, 2, 0, 0),_
  ( 28, 14, 1, 9, 1, 2, 0, 1, 0, 0)_
),_
( 7, 5, 0,_
  ( 16, 0, 0, 8, 0, 4, 0, 2, 7, 0),_
  ( 16, 0, 0, 8, 0, 0, 0, 1, 7, 0),_
  ( 18, 0, 0, 9, 0, 2, 0, 2, 3, 0),_
  ( 18, 0, 0, 9, 0, 3, 0, 1, 3, 0)_
),_
( 4, 5, 0,_
  ( 26, 4, 0, 9, 1, 1, 0, 3, 0, 0),_
  ( 26, 4, 0, 9, 1, 1, 0, 3, 0, 0),_
  ( 26, 4, 0, 9, 1, 1, 0, 1, 0, 0),_
  ( 26, 4, 0, 9, 1, 1, 0, 1, 0, 0)_
),_
( 5, 5, 0,_
  ( 28, 16, 0, 10, 1, 0, 0, 1, 0, 0),_
  ( 28, 16, 0, 10, 1, 0, 0, 1, 0, 0),_
  ( 28, 16, 0, 10, 1, 0, 0, 1, 0, 0),_
  ( 28, 16, 0, 10, 1, 0, 0, 1, 0, 0)_
),_
( 7, 4, 1,_
  ( 18, 0, 4, 5, 0, 0, 0, 1, 0, 2),_
  ( 18, 0, 4, 5, 0, 1, 1, 2, 1, 0),_
  ( 18, 0, 4, 6, 0, 2, 2, 4, 2, 0),_
  ( 18, 0, 4, 6, 0, 6, 3, 8, 3, 0)_
),_
( 6, 3, 0,_
  ( 31, 0, 0, 0, 0, 4, 0, 1, 0, 1),_
  ( 10, 0, 0, 7, 0, 0, 0, 1, 0, 0),_
  ( 10, 0, 0, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 5, 5, 0,_
  ( 31, 14, 0, 10, 1, 0, 0, 2, 0, 0),_
  ( 24, 10, 0, 6, 1, 0, 0, 1, 1, 0),_
  ( 26, 14, 0, 9, 1, 2, 0, 2, 0, 0),_
  ( 28, 14, 0, 9, 1, 4, 0, 4, 0, 0)_
),_
( 7, 2, 4,_
  ( 16, 0, 0, 6, 0, 2, 0, 2, 7, 0),_
  ( 16, 0, 0, 7, 0, 0, 0, 1, 7, 0),_
  ( 18, 0, 0, 6, 0, 2, 0, 2, 3, 0),_
  ( 18, 0, 0, 7, 0, 3, 0, 1, 3, 3)_
),_
( 7, 4, 0,_
  ( 12, 8, 0, 6, 1, 1, 0, 1, 0, 0),_
  ( 15, 8, 0, 6, 1, 4, 0, 1, 1, 0),_
  ( 16, 0, 0, 6, 0, 8, 0, 3, 0, 0),_
  ( 16, 0, 0, 6, 0, 24, 0, 6, 0, 0)_
),_
( 6, 6, 0,_
  ( 31, 0, 0, 0, 0, 6, 0, 1, 0, 0),_
  ( 11, 6, 4, 7, 1, 0, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 7, 4, 2,_
  ( 20, 0, 0, 7, 0, 2, 0, 2, 7, 0),_
  ( 20, 0, 0, 7, 0, 0, 0, 1, 7, 0),_
  ( 20, 0, 0, 8, 0, 0, 0, 2, 3, 3),_
  ( 20, 0, 0, 8, 0, 0, 0, 1, 3, 0)_
),_
( 6, 4, 0,_
  ( 31, 0, 0, 0, 0, 4, 0, 1, 0, 0),_
  ( 12, 0, 0, 6, 0, 0, 0, 1, 1, 0),_
  ( 12, 0, 0, 6, 0, 3, 0, 2, 0, 0),_
  ( 12, 0, 0, 6, 0, 6, 0, 3, 2, 0)_
),_
( 4, 4, 5,_
  ( 31, 0, 0, 0, 0, 4, 0, 1, 0, 0),_
  ( 26, 16, 4, 6, 1, 0, 0, 2, 0, 0),_
  ( 31, 0, 0, 0, 0, 0, 0, 7, 0, 0),_
  ( 26, 16, 5, 6, 0, 16, 0, 1, 0, 3)_
),_
( 5, 4, 0,_
  ( 31, 11, 0, 0, 1, 2, 0, 3, 2, 1),_
  ( 16, 0, 0, 6, 0, 4, 0, 1, 0, 0),_
  ( 16, 0, 0, 6, 0, 4, 0, 3, 0, 0),_
  ( 16, 0, 0, 6, 0, 8, 0, 6, 0, 0)_
),_
( 6, 2, 0,_
  ( 24, 0, 7, 5, 0, 8, 0, 4, 0, 0),_
  ( 24, 0, 7, 5, 0, 0, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 3, 2, 0,_
  ( 31, 0, 0, 0, 0, 8, 0, 3, 0, 0),_
  ( 28, 16, 0, 6, 1, 6, 0, 1, 0, 0),_
  ( 28, 16, 0, 6, 1, 6, 0, 3, 0, 0),_
  ( 28, 16, 0, 6, 1, 0, 0, 1, 0, 0)_
),_
( 5, 4, 5,_
  ( 31, 0, 8, 5, 0, 8, 0, 4, 1, 0),_
  ( 28, 0, 8, 6, 0, 0, 0, 1, 0, 0),_
  ( 28, 0, 8, 6, 0, 0, 0, 2, 0, 2),_
  ( 28, 0, 8, 6, 0, 4, 0, 3, 0, 0)_
),_
( 7, 2, 0,_
  ( 10, 0, 0, 6, 0, 0, 0, 1, 0, 0),_
  ( 10, 0, 1, 6, 0, 0, 0, 1, 0, 0),_
  ( 10, 0, 2, 6, 0, 8, 0, 2, 0, 0),_
  ( 10, 0, 2, 6, 0, 12, 0, 3, 0, 0)_
),_
( 4, 3, 1,_
  ( 22, 0, 0, 0, 0, 7, 0, 3, 0, 1),_
  ( 22, 0, 0, 6, 0, 0, 0, 1, 0, 0),_
  ( 22, 0, 0, 0, 0, 0, 0, 2, 0, 1),_
  ( 22, 0, 0, 6, 0, 0, 0, 1, 0, 0)_
),_
( 4, 6, 2,_
  ( 22, 0, 0, 0, 0, 6, 0, 1, 0, 0),_
  ( 22, 0, 0, 6, 0, 0, 0, 1, 0, 0),_
  ( 22, 0, 0, 0, 0, 0, 0, 3, 0, 1),_
  ( 22, 0, 0, 6, 0, 8, 0, 1, 0, 0)_
),_
( 5, 4, 0,_
  ( 22, 0, 0, 0, 0, 0, 0, 3, 0, 0),_
  ( 22, 0, 6, 6, 0, 0, 0, 1, 0, 0),_
  ( 22, 0, 6, 6, 0, 3, 0, 2, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 7, 5, 0,_
  ( 24, 0, 7, 7, 0, 0, 0, 1, 0, 0),_
  ( 28, 14, 14, 15, 0, 0, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 3, 0, 0,_
  ( 31, 0, 0, 0, 0, 1, 0, 2, 0, 0),_
  ( 31, 0, 0, 0, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
  ( 24, 0, 10, 7, 0, 0, 0, 1, 0, 0)_
),_
( 3, 0, 0,_
  ( 31, 0, 0, 0, 0, 2, 0, 2, 0, 0),_
  ( 31, 0, 0, 0, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
  ( 24, 0, 11, 5, 0, 0, 0, 1, 0, 0)_
),_
( 4, 5, 0,_
  ( 28, 20, 0, 0, 2, 0, 0, 2, 0, 0),_
  ( 28, 0, 13, 7, 0, 0, 0, 1, 0, 0),_
  ( 28, 0, 0, 0, 0, 0, 0, 1, 0, 0),_
  ( 28, 0, 13, 7, 0, 0, 0, 1, 0, 0)_
),_
( 3, 2, 0,_
  ( 18, 0, 0, 7, 0, 2, 0, 1, 0, 0),_
  ( 20, 0, 0, 8, 0, 0, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 20, 0, 0, 8, 0, 0, 0, 1, 0, 0)_
),_
( 3, 0, 0,_
  ( 18, 0, 0, 0, 0, 0, 0, 1, 0, 0),_
  ( 22, 0, 0, 0, 0, 0, 0, 1, 0, 0),_
  ( 18, 0, 0, 0, 0, 8, 0, 2, 0, 0),_
  ( 22, 0, 0, 8, 0, 0, 0, 1, 0, 0)_
),_
( 4, 6, 0,_
  ( 15, 0, 0, 0, 0, 4, 0, 1, 0, 0),_
  ( 17, 0, 0, 11, 0, 0, 0, 1, 0, 0),_
  ( 15, 0, 0, 0, 0, 0, 0, 3, 0, 0),_
  ( 17, 0, 0, 11, 0, 0, 0, 1, 0, 0)_
),_
( 4, 4, 0,_
  ( 31, 0, 10, 6, 0, 2, 0, 5, 0, 0),_
  ( 24, 0, 10, 6, 0, 2, 0, 1, 0, 0),_
  ( 31, 0, 10, 6, 0, 0, 0, 5, 0, 0),_
  ( 24, 0, 10, 6, 0, 4, 0, 4, 0, 0)_
),_
( 5, 5, 6,_
  ( 24, 0, 15, 8, 0, 0, 0, 4, 0, 2),_
  ( 24, 0, 15, 8, 0, 0, 0, 1, 0, 0),_
  ( 22, 0, 15, 8, 0, 2, 0, 3, 0, 0),_
  ( 20, 0, 15, 8, 0, 4, 0, 5, 0, 0)_
),_
( 4, 3, 5,_
  ( 28, 0, 11, 5, 0, 0, 0, 2, 0, 0),_
  ( 28, 0, 11, 6, 0, 0, 0, 1, 0, 0),_
  ( 28, 0, 11, 5, 0, 0, 0, 1, 0, 2),_
  ( 28, 0, 11, 6, 0, 5, 0, 2, 0, 0)_
),_
( 5, 3, 0,_
  ( 31, 0, 0, 0, 0, 0, 0, 5, 0, 0),_
  ( 31, 0, 21, 10, 0, 0, 0, 2, 0, 0),_
  ( 31, 0, 21, 10, 0, 0, 0, 5, 0, 0),_
  ( 31, 0, 21, 10, 0, 0, 0, 7, 0, 0)_
),_
( 6, 7, 0,_
  ( 31, 0, 0, 0, 0, 0, 0, 0, 0, 0),_
  ( 31, 0, 19, 9, 0, 0, 0, 0, 0, 0),_
  ( 31, 0, 13, 6, 0, 4, 0, 1, 0, 0),_
  ( 31, 0, 11, 5, 0, 0, 0, 0, 0, 0)_
),_
( 5, 5, 0,_
  ( 28, 0, 0, 0, 0, 4, 0, 1, 0, 0),_
  ( 28, 0, 17, 8, 0, 0, 0, 0, 0, 0),_
  ( 28, 0, 19, 9, 0, 0, 0, 0, 0, 0),_
  ( 28, 0, 21, 10, 0, 0, 0, 2, 0, 0)_
),_
( 4, 7, 0,_
  ( 31, 0, 0, 0, 0, 0, 0, 0, 0, 0),_
  ( 31, 0, 19, 9, 0, 0, 0, 0, 0, 0),_
  ( 14, 0, 15, 7, 0, 0, 0, 0, 0, 0),_
  ( 31, 0, 11, 5, 0, 0, 0, 0, 0, 0)_
),_
( 6, 7, 6,_
  ( 7, 0, 0, 0, 0, 6, 0, 4, 0, 1),_
  ( 8, 0, 0, 15, 0, 0, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 7, 0, 0,_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 6, 7, 0,_
  ( 17, 0, 17, 8, 0, 0, 0, 15, 0, 0),_
  ( 17, 0, 17, 8, 0, 16, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 6, 7, 0,_
  ( 31, 0, 0, 0, 0, 0, 0, 15, 0, 0),_
  ( 8, 0, 0, 6, 0, 2, 0, 15, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 5, 2, 5,_
  ( 31, 0, 0, 0, 0, 0, 0, 12, 0, 1),_
  ( 16, 0, 0, 7, 0, 2, 0, 3, 0, 0),_
  ( 16, 0, 0, 7, 0, 4, 0, 9, 0, 0),_
  ( 16, 0, 0, 7, 0, 6, 0, 12, 0, 0)_
),_
( 5, 4, 5,_
  ( 31, 0, 0, 0, 0, 0, 0, 13, 0, 0),_
  ( 31, 0, 0, 8, 0, 0, 0, 2, 0, 1),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 6, 7, 5,_
  ( 31, 0, 0, 0, 0, 0, 0, 15, 0, 0),_
  ( 31, 0, 0, 8, 0, 0, 0, 0, 0, 3),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
),_
( 5, 7, 6,_
  ( 31, 0, 0, 0, 0, 0, 0, 15, 0, 0),_
  ( 8, 0, 0, 6, 0, 0, 0, 4, 0, 3),_
  ( 8, 0, 0, 6, 0, 0, 0, 8, 0, 3),_
  ( 8, 0, 0, 6, 0, 0, 0, 12, 0, 3)_
),_
( 5, 7, 0,_
  ( 31, 0, 0, 0, 0, 0, 0, 11, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 11, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0)_
)}

dim shared as DRUMPARAMETER drums (35 to 81) = {_
( 5, 0, 0,_
  ( 31, 0, 17, 8, 0, 0, 0, 3, 0, 0),_
  ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 11, 8192, 35),_
( 5, 0, 0,_
  ( 31, 0, 15, 7, 0, 0, 0, 3, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
 14, 8192, 36),_
( 6, 7, 0,_
  ( 31, 0, 19, 9, 0, 0, 0, 3, 0, 0),_
  ( 31, 0, 19, 9, 0, 4, 0, 2, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
 59, 8192, 37),_
( 5, 7, 0,_
  ( 31, 0, 0, 0, 0, 0, 0, 15, 0, 0),_
  ( 31, 24, 17, 8, 0, 0, 0, 1, 0, 0),_
  ( 31, 24, 17, 8, 0, 0, 0, 1, 0, 0),_
  ( 31, 24, 17, 8, 0, 0, 0, 1, 0, 0),_
 48, 8192, 38),_
( 5, 7, 0,_
  ( 31, 0, 0, 0, 0, 0, 0, 15, 0, 0),_
  ( 31, 0, 19, 9, 0, 0, 0, 1, 1, 0),_
  ( 31, 0, 19, 9, 0, 0, 0, 1, 2, 0),_
  ( 31, 0, 19, 9, 0, 0, 0, 1, 3, 0),_
 87, 6912, 39),_
( 5, 7, 0,_
  ( 31, 0, 0, 0, 0, 0, 0, 15, 0, 0),_
  ( 31, 0, 19, 9, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 19, 9, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 19, 9, 0, 0, 0, 1, 0, 0),_
 55, 8192, 40),_
( 5, 0, 0,_
  ( 31, 0, 15, 7, 0, 0, 0, 3, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
 14, 4352, 41),_
( 6, 7, 0,_
  ( 31, 0, 0, 0, 0, 0, 0, 2, 0, 0),_
  ( 31, 0, 21, 10, 0, 0, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
 99, 10752, 42),_
( 5, 0, 0,_
  ( 31, 0, 15, 7, 0, 0, 0, 3, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
 18, 5888, 43),_
( 6, 7, 0,_
  ( 31, 0, 0, 0, 0, 0, 0, 2, 0, 0),_
  ( 31, 0, 21, 10, 0, 0, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
 100, 10752, 42),_
( 5, 0, 0,_
  ( 31, 0, 15, 7, 0, 0, 0, 3, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
 20, 7424, 45),_
( 6, 7, 0,_
  ( 31, 0, 0, 0, 0, 0, 0, 2, 0, 0),_
  ( 31, 0, 13, 6, 0, 0, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
 100, 10752, 42),_
( 5, 0, 0,_
  ( 31, 0, 15, 7, 0, 0, 0, 3, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
 24, 8960, 47),_
( 5, 0, 0,_
  ( 31, 0, 15, 7, 0, 0, 0, 3, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
 27, 10496, 48),_
( 5, 7, 3,_
  ( 31, 0, 0, 0, 0, 0, 0, 8, 0, 1),_
  ( 31, 20, 11, 5, 1, 0, 0, 2, 0, 0),_
  ( 31, 20, 11, 5, 2, 0, 0, 3, 0, 0),_
  ( 31, 20, 11, 5, 3, 0, 0, 5, 0, 0),_
 104, 10752, 49),_
( 5, 0, 0,_
  ( 31, 0, 15, 7, 0, 0, 0, 3, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 15, 7, 0, 0, 0, 1, 0, 0),_
 31, 12032, 50),_
( 5, 7, 0,_
  ( 31, 0, 0, 0, 0, 6, 0, 8, 0, 0),_
  ( 31, 0, 11, 5, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 11, 5, 0, 0, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
 97, 5632, 51),_
( 5, 7, 3,_
  ( 31, 0, 0, 0, 0, 0, 0, 2, 0, 1),_
  ( 31, 0, 11, 5, 0, 0, 0, 1, 0, 0),_
  ( 31, 0, 11, 5, 0, 0, 0, 1, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 1, 0, 0),_
 94, 5632, 52),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
(7,7,0,_
 ( 31, 0, 17, 8, 0, 0, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
 ( 31, 0, 0, 15, 0, 127, 0, 1, 0, 0),_
36,8192,1),_
( 5, 4, 0,_
  ( 31, 0, 10, 0, 0, 0, 0, 15, 0, 0),_
  ( 31, 24, 17, 8, 0, 0, 0, 15, 0, 0),_
  ( 31, 24, 17, 8, 0, 0, 0, 15, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 15, 0, 0),_
 72, 3072, 80),_
( 5, 4, 0,_
  ( 31, 0, 5, 0, 0, 0, 0, 15, 0, 0),_
  ( 31, 24, 13, 6, 0, 0, 0, 15, 0, 0),_
  ( 31, 24, 13, 6, 0, 0, 0, 15, 0, 0),_
  ( 31, 31, 31, 15, 0, 127, 0, 15, 0, 0),_
 72, 3072, 80)}


midisynth.bi

Code: Select all

const m_pi=3.14159265358979323846

type sine_wave_generator
        declare sub set_cycle(cycle as single)
        declare sub add_modulation(x as long)
        declare function get_next() as integer
        declare function get_next(modulation as long) as integer

        position as unsigned long
        _step as unsigned long
end type

enum ADSR
   ATTACK
   ATTACK_RELEASE
   DECAY
   DECAY_RELEASE
   SUSTAIN
   RELEASE
   SOUNDOFF
   FINISHED
end enum

type envelope_generator
        declare sub set_rate(rate as single)
        declare sub set_hold(value as single)
        declare sub set_freeze(value as single)
        declare sub key_off()
        declare sub sound_off()
        declare function get_next() as integer

        state as ADSR
        AR as integer
        DR as integer
        SR as integer
        RR as integer
        TL as integer
        fAR as unsigned long
        fDR as unsigned long
        fSR as unsigned long
        fRR as unsigned long
        fSL as unsigned long
        fTL as unsigned long
        _fOR as unsigned long
        fSS as unsigned long
        fDRR as unsigned long
        fDSS as unsigned long
        current as unsigned long
        rate as single
        hold as single
        freeze as single
        declare sub update_parameters()
end type

type fm_operator
        declare sub set_freq_rate(freq as single, rate as single)
        declare function get_next() as integer
        declare function get_next(modulate as integer) as integer
        declare function get_next(lfo as integer, modulate as integer) as integer

        swg as sine_wave_generator
        eg as envelope_generator
        ML as single
        DT as single
        ams_factor as long
        ams_bias as long
end type

type fm_sound_generator
        declare sub set_rate(rate as single)
        declare sub set_frequency_multiplier(value as single)
        declare sub set_damper(damper as integer)
        declare sub set_sostenute(sostenute as integer)
        declare sub set_freeze(freeze as integer)
        declare sub set_tremolo(depth as integer, frequency as single)
        declare sub set_vibrato(depth as single, frequency as single)
        declare sub key_off()
        declare sub sound_off()
        declare function is_finished() as integer
        declare function get_next() as integer

        op1 as fm_operator
        op2 as fm_operator
        op3 as fm_operator
        op4 as fm_operator
        ams_lfo as sine_wave_generator
        vibrato_lfo as sine_wave_generator
        tremolo_lfo as sine_wave_generator
        ALG as integer
        FB as integer
        freq as single
        freq_mul as single
        ams_freq as single
        ams_enable as integer
        tremolo_depth as integer
        tremolo_freq as single
        vibrato_depth as integer
        vibrato_freq as single
        rate as single
        feedback as integer
        damper as integer
        sostenute as integer
end type


Type fm_note
        declare function synthesize(buf as long ptr, samples as uinteger, rate as single, _left as long, _right as long) as integer
        'declare sub note_off(velocity as integer)
        'declare sub sound_off()
        'declare sub set_frequency_multiplier(value as single)
        'declare sub set_tremolo(depth as integer, freq as single)
        'declare sub set_vibrato(depth as single, freq as single)
        'declare sub set_damper(value as integer)
        'declare sub set_sostenute(value as integer)
        'declare sub set_freeze(value as integer)

        declare sub release()

        assign as integer
        panpot as integer

        fm as fm_sound_generator
        velocity as integer

end type

type FMPARAMETEROP
        AR as integer
        DR as integer
        SR as integer
        RR as integer
        SL as integer
        TL as integer
        KS as integer
        ML as integer
        DT as integer
        AMS as integer
end type

type FMPARAMETER
        ALG as integer
        FB as integer
        LFO as integer
        op1 as FMPARAMETEROP
        op2 as FMPARAMETEROP
        op3 as FMPARAMETEROP
        op4 as FMPARAMETEROP
end type

type DRUMPARAMETER
        ALG as integer
        FB as integer
        LFO as integer
        op1 as FMPARAMETEROP
        op2 as FMPARAMETEROP
        op3 as FMPARAMETEROP
        op4 as FMPARAMETEROP
        key as integer
        panpot as integer
        assign as integer
end type


type fm_note_factory
        declare function note_on(program as long, note as integer, velocity as integer, frequency_multiplier as single) as fm_note ptr

        declare sub clear_

        programs(128) as FMPARAMETER ptr
        drums(128) as DRUMPARAMETER ptr

end type

type _NOTES
   note as fm_note ptr
   key as integer
   status as integer

   _prev as _NOTES ptr
   _next as _NOTES ptr
end type

type channel:
        declare function synthesize(out as long ptr, samples as uinteger, rate as single, master_volume as long, master_balance as integer) as integer
        declare sub reset_all_parameters()
        declare sub reset_all_controller()
        declare sub all_note_off()
        declare sub all_sound_off()
        declare sub all_sound_off_immediately()

        declare sub note_off(note as integer, velocity as integer)
        declare sub note_on(note as integer, velocity as integer)
        declare sub polyphonic_key_pressure(note as integer, value as integer)
        declare sub channel_pressure(value as integer)
        declare sub control_change(control as integer, value as integer)
        declare sub bank_select(value as integer)

        declare sub set_damper(value as integer)
        declare sub set_sostenute(value as integer)
        declare sub set_freeze(value as integer)

        notes as _NOTES ptr
   _firstnote as _NOTES ptr
   _lastnote as _NOTES ptr      'Linked list

        factory as fm_note_factory ptr
        default_bank as integer
        program as integer
        bank as integer
        panpot as integer
        volume as integer
        expression as integer
        pressure as integer
        pitch_bend as integer
        pitch_bend_sensitivity as integer
        modulation_depth as integer
        modulation_depth_range as integer
        damper as integer
        sostenute as integer
        freeze as integer
        fine_tuning as integer
        coarse_tuning as integer
        RPN as integer
        NRPN as integer
        mono as integer
        mute as integer
        tremolo_frequency as single
        vibrato_frequency as single
        frequency_multiplier as single
        master_frequency_multiplier as single
        system_mode as integer

        declare function get_registered_parameter() as integer
        declare sub set_registered_parameter(value as integer)
        declare sub update_frequency_multiplier()
        declare sub update_modulation()
end type

type synthesizer
        declare function synthesize(_output as short ptr, samples as uinteger, rate as single) as integer
        declare function synthesize_mixing(_output as long ptr, samples as uinteger, rate as single) as integer
        declare sub reset()
        declare sub reset_all_parameters()
        declare sub reset_all_controller()
        declare sub all_note_off()
        declare sub all_sound_off()
        declare sub all_sound_off_immediately()

        declare sub sysex_message(pvdata as string)
        declare sub midi_event(_command as integer, param1 as integer, param2 as integer)

        declare sub set_system_mode(mode as integer)

        channels(15) as channel
        active_sensing as single
        main_volume as integer
        master_volume as integer
        master_balance as integer
        master_fine_tuning as integer
        master_coarse_tuning as integer
        master_frequency_multiplier as single
        system_mode as integer
        declare sub update_master_frequency_multiplier()
end type
Last edited by angros47 on May 16, 2018 21:41, edited 1 time in total.
DOS386
Posts: 798
Joined: Jul 02, 2005 20:55

Re: Cross-platform MIDI in pure FreeBasic!

Postby DOS386 » Dec 18, 2013 10:11

> Since some users complained about the lack of a way to play MIDI files on all
> platforms (most solutions are windows-only), here is a solution.

COOL :-)

Suggestion: option to save a WAV file instead of using "alsathread.bas" or "winmmthread.bas".

> (if zippyshare does not work)

Other ideas:

- put it on freebasic-portal
or
- remove binaries, TAR, ZIP, B64 -> cca 60 KiB -> upload to some "pasta"
angros47
Posts: 1421
Joined: Jun 21, 2005 19:04

Re: Cross-platform MIDI in pure FreeBasic!

Postby angros47 » Dec 18, 2013 16:02

This is a version that can save in to a .wav file (I used a modified version of a routine by d.j.peters to prepare the header of the file)

Code: Select all

#include "midisynth.bi"
#include "instruments.bi"
common shared synth as synthesizer




#define FCC(c) *(cptr(Uinteger Ptr,@##c))

Sub PrepareBuffer(Byval filenum As integer, Byval nRate     As Uinteger=44100)
           
  Dim As Uinteger  h (10)
  Dim As Uinteger     BlkAlign=4

  h( 0)=FCC("RIFF")                ' RIFF chunk
  h( 1)=0                          ' size of WAVE chunk + data size
  h( 2)=FCC("WAVE")                ' WAVE chunk
  h( 3)=FCC("fmt ")                ' fmt chunk
  h( 4)=16                         ' size of fmt chunk
  h( 5)=(2 Shl 16) Or 1            ' channels + PCM_FORMAT flag
  h( 6)=nRate                      ' playback rate
  h( 7)=BlkAlign*nRate             ' bytes per sec.
  h( 8)=(16 Shl 16) Or BlkAlign    ' bits per sample + blockalign
  h( 9)=FCC("data")                ' data chunk
  h(10)=0                          ' size of data chunk


  put #filenum, 1, h()
End Sub


dim shared size as integer

dim shared completed as integer


    sub _SoundThread(ByVal userdata As Any Ptr )

            const buffersize=441*2'128*32
       Dim As Short lpBuffers (buffersize)

            do until completed

           synth.synthesize(@lpBuffers(0), Buffersize/2, 44100)
                put #15, , lpBuffers()
           size+=Buffersize
           sleep 10


       loop


    end sub












'based on RealMIDI 2.00, by Sebastian Mate


dim thread_handle as any ptr
dim thread_count as uinteger ptr

open"out.wav" for binary as #15
preparebuffer 15


thread_handle = threadcreate( @_SoundThread)


synth.reset
synth.channels(9).program=120 shl 14      'Set percussion mode







sub MidiMessage (a as string, b as byte, c as byte)
synth.midi_event (asc(a),b,c)
end sub

DIM SHARED Header AS STRING * 4
DIM SHARED TweeByte AS STRING * 2
DIM SHARED VierByte AS STRING * 4
DIM SHARED FileType AS STRING * 2


FUNCTION NextNumber as ubyte
 dim a as string*1
 GET #1, , a
 NextNumber = ASC(a)
END FUNCTION

FUNCTION Nibble (Cr as string, Lr as integer) as string
 ' A Nibble are 4 Bit or a half byte. Strange name!

 IF Lr = 1 THEN
    return LEFT(HEX(ASC(Cr) AND 240), 1)
  ELSE
   return RIGHT(HEX(ASC(Cr) AND 15), 1)
 END IF
END FUNCTION

FUNCTION ReadVarLen as integer
 dim a as string*1
 GET #1, , a
 dim as integer Value, Value2
 Value = ASC(a)
 IF (Value AND 128) THEN
  Value = (Value AND 127)
  DO
   GET #1, , a
   Value2 = ASC(a)
   Value = (Value * (2 ^ 7)) + (Value2 AND 127)
  LOOP WHILE (Value2 AND 128)
 END IF
 return Value
END FUNCTION

FUNCTION Nibble2Number (nib as string) as integer
 SELECT CASE nib
   CASE "0": Nibble2Number = 0
   CASE "1": Nibble2Number = 1
   CASE "2": Nibble2Number = 2
   CASE "3": Nibble2Number = 3
   CASE "4": Nibble2Number = 4
   CASE "5": Nibble2Number = 5
   CASE "6": Nibble2Number = 6
   CASE "7": Nibble2Number = 7
   CASE "8": Nibble2Number = 8
   CASE "9": Nibble2Number = 9
   CASE "A": Nibble2Number = 10
   CASE "B": Nibble2Number = 11
   CASE "C": Nibble2Number = 12
   CASE "D": Nibble2Number = 13
   CASE "E": Nibble2Number = 14
   CASE "F": Nibble2Number = 15
 END SELECT
END FUNCTION

FUNCTION ReadBPM as long
 DIM temp AS LONG
 dim a as string*1
 GET #1, , a
 IF a = CHR(3) THEN
  FOR i as integer = 1 TO 3
   GET #1, , a
   temp = (temp * 256) + ASC(a)
  NEXT i
 END IF
 return temp
END FUNCTION

FUNCTION ReadFourBytes as long
 dim t as long
 dim a as string*1
 GET #1, , a
 t = ASC(a) * 2 ^ 8
 GET #1, , a
 t = (ASC(a) + t) * 2 ^ 8
 GET #1, , a
 t = (ASC(a) + t) * 2 ^ 8
 GET #1, , a
 ReadFourBytes = t + ASC(a)
END FUNCTION

FUNCTION ReadText as string
 dim a as string*1
 dim temp as string
 dim as integer Lengte = ReadVarLen
 FOR tt as integer= 1 TO Lengte
  GET #1, , a
  temp = temp + a
 NEXT tt
 return temp
END FUNCTION

FUNCTION ReadTimeSignature as string
 dim a as string*1
 dim as integer t1,t2

 GET #1, , a
 GET #1, , a: T1 = ASC(a)
 GET #1, , a: T2 = ASC(a)
 GET #1, , a
 GET #1, , a

 return STR(T1) + " /" + STR(2 ^ T2)

END FUNCTION

FUNCTION ReadTwoBytes as short
 dim a as string*1
 dim t as integer
 GET #1, , a
 t = ASC(a) * 2 ^ 8
 GET #1, , a
 return t + ASC(a)
END FUNCTION



var file="TIMEWRP.MID"

 OPEN file FOR BINARY AS #1
 GET #1, , Header
 IF Header <> "MThd" THEN PRINT "Not a valid MIDI file": STOP
 GET #1, , VierByte
 GET #1, , FileType
 IF ASC(RIGHT(FileType, 1)) = 0 THEN
 ELSE
   PRINT "Multy tracks, this file type is not supported.": END
 END IF

 dim Tracks as integer, Tempo as integer
 Tracks = ReadTwoBytes
 tempo = ReadTwoBytes
 GET #1, , Header
 var TrkLengte = ReadFourBytes '+ LOC(1)

 dim lyric as string, a as string*1
 dim as string t2, n
 dim as integer tl
 



 do until eof(1)
     tl = ReadVarLen ' Read the delay until we do anything and delay:
     dim as double startDelay=timer

     do:loop until timer>=StartDelay+(tl / tempo/1.5)
      'FOR ar% = 1 TO MDelay%
      ' FOR Wacht = 1 TO tl * (1.5 / tempo) * 100 * WL: NEXT Wacht
      'NEXT ar%
     
if inkey<>"" then exit do

     GET #1, , a ' Get the MIDI-command...
     IF a = CHR(255) THEN '... we have a meta-command!
       GET #1, , a
       SELECT CASE ASC(a)
   CASE 0:  PRINT "Sequence Number : "; ReadText
   CASE 1: lyric = ReadText:'print lyric;
   CASE 32: PRINT "MIDI ch. Prefix.. ": a = ReadText: REM <====== What is this ?
   CASE 47: end
   CASE 81: tempo = (60000000 / ReadBPM)
   CASE 84: PRINT "SMPTE Offset    : "; : T2 = ReadText$
   CASE 88 ' Time signature
     N = ReadTimeSignature
   CASE 89 ' Key signature
     N = ReadText
   CASE 127 'Sequencer-specific Meta Event
     N = ReadText
   CASE ELSE
   T2 = ReadText ' Unkown Meta Event
       END SELECT
      ELSE

      IF HEX(ASC(a)) = "F0" OR HEX(ASC(a)) = "F7" THEN
   T2 = ReadText
      ELSE

       IF Nibble(a, 1) = "8" THEN 'Send: Tune Off
   var first=NextNumber
   var Second=NextNumber
   MidiMessage a,first, second
       END IF

       IF Nibble$(a, 1) = "9" THEN 'Send: Tune On
   var first=NextNumber
   var Second=NextNumber

   MidiMessage a,first, second
       END IF

       IF Nibble$(a, 1) = "A" THEN 'Key after-touch
   MidiMessage a,NextNumber, 0
       END IF

       IF Nibble$(a, 1) = "B" THEN
   'MidiMessage a,NextNumber, NextNumber
   NextNumber:NextNumber
       END IF


       IF Nibble$(a, 1) = "C" THEN ' Change voice
   MidiMessage a,NextNumber, 0
   synth.channels(9).program=120 shl 14      'Set percussion mode

       END IF

      IF Nibble$(a, 1) = "D" THEN ' <- ???
   MidiMessage a,NextNumber, 0
      END IF

      IF Nibble$(a, 1) = "E" THEN 'Pitch wheel change
   var first=NextNumber
   var Second=NextNumber
   MidiMessage a,first, second
      END IF

   END IF
   END IF
 loop


completed=1
put #15, 41, size
size+=36
put #15, 5, size
chrowle
Posts: 47
Joined: Oct 21, 2013 23:32
Location: Alberta, Canada

Re: Cross-platform MIDI in pure FreeBasic!

Postby chrowle » Jan 30, 2014 20:15

This reminds me a bit of your adlib PLAY replacement.
angros47
Posts: 1421
Joined: Jun 21, 2005 19:04

Re: Cross-platform MIDI in pure FreeBasic!

Postby angros47 » May 16, 2018 21:42

Here is a remade sequencer

Code: Select all

#include "midisynth.bi"
#include "instruments.bi"

'based on RealMIDI 2.00, by Sebastian Mate


dim thread_handle as any ptr
dim thread_count as uinteger ptr
declare sub _SoundThread(ByVal userdata As Any Ptr )
declare sub _SoundInit()

_SoundInit
thread_handle = threadcreate( @_SoundThread)

common shared synth as synthesizer

synth.reset
synth.channels(9).program=120 shl 14      'Set percussion mode







sub MidiMessage (a as ubyte, b as byte, c as byte)
synth.midi_event (a,b,c)
end sub



DIM SHARED Header AS STRING * 4
DIM SHARED TweeByte AS STRING * 2
DIM SHARED VierByte AS STRING * 4
DIM SHARED FileType AS STRING * 2


FUNCTION NextNumber as ubyte
 dim a as ubyte
 GET #1, , a
 NextNumber = a
END FUNCTION


FUNCTION ReadVarLen as integer
 dim a as ubyte
 GET #1, , a
 dim as integer Value, Value2
 Value = a
 IF (Value AND 128) THEN
  Value = (Value AND 127)
  DO
   GET #1, , a
   Value2 = a
   Value = (Value * (2 ^ 7)) + (Value2 AND 127)
  LOOP WHILE (Value2 AND 128)
 END IF
 return Value
END FUNCTION


FUNCTION ReadBPM as long
 DIM temp AS LONG
 dim a as ubyte
 GET #1, , a
 IF a = 3 THEN
  FOR i as integer = 1 TO 3
   GET #1, , a
   temp = (temp * 256) + a
  NEXT i
 END IF
 return temp
END FUNCTION

FUNCTION ReadFourBytes as long
 dim t as long
 dim a as ubyte
 GET #1, , a
 t = a * 2 ^ 8
 GET #1, , a
 t = (a + t) * 2 ^ 8
 GET #1, , a
 t = (a + t) * 2 ^ 8
 GET #1, , a
 ReadFourBytes = t + a
END FUNCTION

sub ReadText
 dim a as ubyte
 dim as integer Lengte = ReadVarLen
 FOR tt as integer= 1 TO Lengte
  GET #1, , a
 NEXT tt
END sub


FUNCTION ReadTwoBytes as short
 dim a as ubyte
 dim t as integer
 GET #1, , a
 t = a * 2 ^ 8
 GET #1, , a
 return t + a
END FUNCTION



var file=command

 OPEN file FOR BINARY AS #1
 GET #1, , Header
 IF Header <> "MThd" THEN PRINT "Not a valid MIDI file": STOP
 GET #1, , VierByte
 GET #1, , FileType
' IF ASC(RIGHT(FileType, 1)) = 0 THEN
' ELSE
'   PRINT "Multy tracks, this file type is not supported.": END
' END IF

 dim Tracks as integer, Divisions as integer, Tempo as integer=60000000/120
 Tracks = ReadTwoBytes
 Divisions = ReadTwoBytes

 dim Track as String
 dim Sequence(Tracks) as String
dim LastPos as integer
for tr as integer=0 to Tracks
    if eof(1) then exit for
    GET #1, , Header

    Track=""
    var TrkLength = ReadFourBytes

    LastPos=LOC(1)-2

    dim a as ubyte, status as ubyte
    dim as integer tl
 

    dim SeqTime as Double
    dim i as integer
    do
        if LOC(1)-LastPos>TrkLength orelse eof (1) then exit do
        tl = ReadVarLen ' Read the delay until we do anything and delay:
        'dim as double startDelay=timer

        'do:loop until timer>=StartDelay+(tl / tempo/1.5)
        SeqTime+=(tl * tempo/Divisions/1e6)
        

        GET #1, , a ' Get the MIDI-command...

        IF a = 255 THEN '... we have a meta-command!
          GET #1, , a
          SELECT CASE a
      CASE 47: NextNumber 'End of track
      CASE 81: tempo = ReadBPM
      CASE ELSE
        ReadText ' Unkown Meta Event
          END SELECT
         ELSEIF a = &HF0 OR a = &HF7 THEN
      ReadText
         ELSE

          if a>127 then status=a: GET #1, , a
          SELECT CASE status shr 4
          case &H8, &H9, &HA, &HB, &HE 
      Track+=mkd(SeqTime)
      Track+=chr(status)
      Track+=chr(a)
      Track+=chr(NextNumber)



          case &HC, &HD
      Track+=mkd(SeqTime)
      Track+=chr(status)
      Track+=chr(a)
      Track+=chr(0)
          case else
      exit do



          End Select




      END IF
    loop


    Sequence(tr)=Track
next
?"Start"

dim as double startDelay=timer
dim p(Tracks) as integer

for i as integer=0 to Tracks
   p(i)=1
next
dim as integer isPlaying
do
   isPlaying=0
   for i as integer=0 to Tracks
      
      if p(i)<len(Sequence(i)) then
           isPlaying=1
           dim SeqTime as Double=cvd(mid(Sequence(i),p(i)))

           if timer>=StartDelay+SeqTime then
             dim a as ubyte, b as ubyte, c as ubyte
             a=asc(mid(Sequence(i),p(i)+8))
             b=asc(mid(Sequence(i),p(i)+9))
             c=asc(mid(Sequence(i),p(i)+10))

             if a<>&H99 orelse (b>=35 andalso b<=81) then MidiMessage(a,b,c)
             synth.channels(9).program=120 shl 14      'Set percussion mode
             p(i)+=11
           end if
      end if
   next
      

loop while isPlaying
coderJeff
Site Admin
Posts: 2695
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Cross-platform MIDI in pure FreeBasic!

Postby coderJeff » Jun 09, 2018 15:40

I really want to try this. Where is _soundinit() and _soundthread() defined? Is there another source file to get?

Return to “Projects”

Who is online

Users browsing this forum: No registered users and 0 guests