Midi File decoder

Share your advanced PureBasic knowledge/code with the community.
zapman*
Enthusiast
Enthusiast
Posts: 115
Joined: Wed Jun 02, 2004 10:17 pm
Location: New Caledonia (South Pacific)
Contact:

Midi File decoder

Post by zapman* »

Code: Select all

; MIDI File decoder by Zapman

Declare.s ReadStringl(Length.l)
Declare ReadVLD ()
Declare ReadMidiFile()

Dim MidiInstrument$ (127)
Restore SMI
For ct = 0 To 127
  Read MidiInstrument$(ct)
Next

ReadMidiFile()
;
Procedure ReadMidiFile()
  MidiFileName$= OpenFileRequester("", ".MID", ".MID", 0) 
  If ReadFile(0, MidiFileName$)
    ChkName$ = ReadStringl(4)
    ChkLength = (ReadByte()*256*256*256)+(ReadByte()*256*256)+(ReadByte()*256)+ReadByte()
    If ChkName$<>"MThd" Or ChkLength <> 6
      MessageRequester("Error","Unknown format !! : "+ChkName$+" / "+Str(ChkLength),0)
      ProcedureReturn(0)
    EndIf
    mloc = Loc()
    MFormatType = ReadByte()*256+ReadByte()
    Debug "FormatType = "+Str(MFormatType )
    NbOfMTrk = ReadByte()*256+ReadByte()
    Debug "Number of tracks = "+Str(NbOfMTrk)
    DeltaTimeIncrement = ReadByte()*256+ReadByte()
    Debug "DeltaTimeIncrement  = "+Str(DeltaTimeIncrement)
    FileSeek(mloc+ChkLength)
    While NbOfMTrk
      ChkName$ = ReadStringl(4)
      If ChkName$=""
        MessageRequester("Error","Abnormal EndOfFile encountered.",0)
        ProcedureReturn(0)
      EndIf
      ChkLength = (ReadByte()*256*256*256)+(ReadByte()*256*256)+(ReadByte()*256)+ReadByte()
      NbOfMTrk - 1
      If ChkName$<>"MTrk"
        Debug "Unknown Track Type: "+ChkName$
        FileSeek(Loc()+ChkLength)
      Else
        ContRead = 1
        While ContRead
        Delta_time = ReadVLD ()
        MEvent = ReadByte() : If MEvent<0 : MEvent+256 : EndIf
        If MEvent = $F0 Or MEvent = $F7 ; SYSEX Event
          Debug "SYSEX Event"
          LEvent = ReadVLD ()
          FileSeek(Loc()+LEvent)
        ElseIf MEvent = $FF ; Meta Event
          TEvent = ReadByte()
          ;Debug "Meta Event type : "+Str(TEvent)
          RS = 1
          Select TEvent
            Case 0
              MetaEvent$ = "Sequence Number"
              RS = 0
              SeqNumberYesNo = ReadByte()
              If SeqNumberYesNo
                MIDICue = ReadByte()*256 + ReadByte()
                MetaEvent$+" - MidiCue: "+Str(MIDICue)
              EndIf
            Case 1
              MetaEvent$ = "Text"
            Case 2
              MetaEvent$ = "Copyright"
            Case 3
              MetaEvent$ = "Sequence/Track Name"
            Case 4
              MetaEvent$ = "Instrument Name"
            Case 5
              MetaEvent$ = "Lyric"
            Case 6
              MetaEvent$ = "Marker"
            Case 7
              MetaEvent$ = "Cue Point"
            Case 8
              MetaEvent$ = "Program Name"
            Case 9
              MetaEvent$ = "Device Name"
            Case $20
              MetaEvent$ = "MIDI Channel Prefix"
            Case $21 
              MetaEvent$ = "MIDI Port"
            Case $2F
              MetaEvent$ = "End of Track"
              RS = 0
              ReadByte()
              ContRead = 0
            Case $51
              MetaEvent$ = "Set Tempo, in microseconds per MIDI quarter-note"
              RS = 0
              ReadByte()
              MTempo = ReadByte()*256*256 + ReadByte()*256 + ReadByte()
              MetaEvent$ + ": "+Str(MTempo)
            Case $54
              MetaEvent$ = "SMPTE Offset"
              RS = 0
              ReadByte()
              SecOffset = ReadByte()*3600+ReadByte()*60+ReadByte()
              FrameOffset = ReadByte()*100 + ReadByte()
              MetaEvent$+": "+Str(SecOffset)+" sec. and "+Str(FrameOffset)+" 1/100 of frame"
            Case $58
              MetaEvent$ = "Time Signature"
              RS = 0
              ReadByte()
              Numerator = ReadByte()
              Denominator = ReadByte()
              NbOfMidiClockPerMetronomeClick = ReadByte()
              Notated32ndPerQuarterNote = ReadByte()
              
            Case $59
              MetaEvent$ = "Key Signature"
              RS = 0
              ReadByte()
              sf = ReadByte()
              MajorMinor = ReadByte()
            Case $7F
              MetaEvent$ = "Sequencer-Specific Meta-Event"
            Default
              MetaEvent$ = "Unknown Meta-Event ("+Hex(TEvent)+")"
          EndSelect
          If RS
            LEvent = ReadVLD ()
            Debug MetaEvent$+": "+ReadStringl(LEvent )
          Else
            Debug MetaEvent$
          EndIf
        Else
          ; MIDI Event
          
          TEvent = MEvent
          If TEvent<$80 ; This is not an Event. Keep the old Status
            FileSeek(Loc()-1)
            TEvent = mTEvent
          Else
            mTEvent = TEvent
          EndIf
          ;Debug "Midi Event type : "+Hex(TEvent)
          If TEvent >=$80 And TEvent <=$8F
            MNote = ReadByte() : If MNote <0 : MNote + 256 : EndIf
            MVelocity = ReadByte() : If MVelocity <0 : MVelocity + 256 : EndIf
            MidiEvent$ = "Note Off, channel "+Str(TEvent&$F)+" - Note : "+Str(MNote)+" - Velocity : "+Str(MVelocity)
          ElseIf TEvent >=$90 And TEvent <=$9F
            MNote = ReadByte() : If MNote <0 : MNote + 256 : EndIf
            MVelocity = ReadByte() : If MVelocity <0 : MVelocity + 256 : EndIf
            MidiEvent$ ="Note On, channel "+Str(TEvent&$F)+" - Note : "+Str(MNote)+" - Velocity : "+Str(MVelocity)
          ElseIf TEvent >=$A0 And TEvent <=$AF
            MNote = ReadByte() : If MNote <0 : MNote + 256 : EndIf
            MPressure = ReadByte() : If MPressure <0 : MPressure + 256 : EndIf
            MidiEvent$ ="After touch, channel "+Str(TEvent&$F)+" - Note : "+Str(MNote)+" - Pressure : "+Str(MPressure)
          ElseIf TEvent >=$B0 And TEvent <=$BF
            MControlerNumber = ReadByte()
            MValue = ReadByte() : If Mvalue<0 : MValue + 256 : EndIf
            Select MControlerNumber
              Case 0
                ControlerEvent$ = "Bank Select - Coarse: "+Str(MValue)
              Case 32
                ControlerEvent$ = "Bank Select - Fine: "+Str(MValue)
              Case 1
                ControlerEvent$ = "MOD Wheel - Coarse: "+Str(MValue)
              Case 33
                ControlerEvent$ = "MOD Wheel - Fine: "+Str(MValue)
              Case 2
                ControlerEvent$ = "Breath Control - Coarse: "+Str(MValue)
              Case 34
                ControlerEvent$ = "Breath Control - Fine: "+Str(MValue)
              Case 4
                ControlerEvent$ = "Foot Pedal - Coarse: "+Str(MValue)
              Case 36
                ControlerEvent$ = "Foot Pedal - Fine: "+Str(MValue)
              Case 5
                ControlerEvent$ = "Portamento Time - Coarse: "+Str(MValue)
              Case 37
                ControlerEvent$ = "Portamento Time - Fine: "+Str(MValue)
              Case 6
                ControlerEvent$ = "Data Slider - Coarse: "+Str(MValue)
              Case 38
                ControlerEvent$ = "Data Slider - Fine: "+Str(MValue)
              Case 7
                ControlerEvent$ = "Volume - Coarse: "+Str(MValue)
              Case 39
                ControlerEvent$ = "Volume - Fine: "+Str(MValue)
              Case 8
                ControlerEvent$ = "Balance - Coarse: "+Str(MValue)
              Case 40
                ControlerEvent$ = "Balance - Fine: "+Str(MValue)
              Case 10
                ControlerEvent$ = "Pan - Coarse: "+Str(MValue)
              Case 42
                ControlerEvent$ = "Pan - Fine: "+Str(MValue)
              Case 11
                ControlerEvent$ = "Expression - Coarse: "+Str(MValue)
              Case 43
                ControlerEvent$ = "Expression - Fine: "+Str(MValue)
              Case 12
                ControlerEvent$ = "Effect 1 - Coarse: "+Str(MValue)
              Case 44
                ControlerEvent$ = "Effect 1 - Fine: "+Str(MValue)
              Case 13
                ControlerEvent$ = "Effect 2 - Coarse: "+Str(MValue)
              Case 45
                ControlerEvent$ = "Effect 2 - Fine: "+Str(MValue)
              Case 16
                ControlerEvent$ = "General Purpose 1: "+Str(MValue)
              Case 17
                ControlerEvent$ = "General Purpose 2: "+Str(MValue)
              Case 18
                ControlerEvent$ = "General Purpose 3: "+Str(MValue)
              Case 19
                ControlerEvent$ = "General Purpose 4: "+Str(MValue)
              Case 64
                ControlerEvent$ = "Hold Pedal: "
                If MValue >0 And MValue<64
                  ControlerEvent$+"On"
                Else
                  ControlerEvent$+"Off"
                EndIf
              Case 65
                ControlerEvent$ = "Portamento: "
                If MValue >0 And MValue<64
                  ControlerEvent$+"On"
                Else
                  ControlerEvent$+"Off"
                EndIf
              Case 66
                ControlerEvent$ = "Sustenuto: "
                If MValue >0 And MValue<64
                  ControlerEvent$+"On"
                Else
                  ControlerEvent$+"Off"
                EndIf
              Case 67
                ControlerEvent$ = "Soft Pedal: "
                If MValue >0 And MValue<64
                  ControlerEvent$+"On"
                Else
                  ControlerEvent$+"Off"
                EndIf
              Case 68
                ControlerEvent$ = "Legato Pedal: "
                If MValue >0 And MValue<64
                  ControlerEvent$+"On"
                Else
                  ControlerEvent$+"Off"
                EndIf
              Case 69
                ControlerEvent$ = "Hold 2 Pedal: "
                If MValue >0 And MValue<64
                  ControlerEvent$+"On"
                Else
                  ControlerEvent$+"Off"
                EndIf
              Case 70
                ControlerEvent$ = "Sound Variation: "+Str(MValue)
              Case 71
                ControlerEvent$ = "Sound Timbre: "+Str(MValue)
              Case 72
                ControlerEvent$ = "Release Time: "+Str(MValue)
              Case 73
                ControlerEvent$ = "Attack Time: "+Str(MValue)
              Case 74
                ControlerEvent$ = "Sound Brightness: "+Str(MValue)
              Case 75
                ControlerEvent$ = "Sound Control 1: "+Str(MValue)
              Case 76
                ControlerEvent$ = "Sound Control 2: "+Str(MValue)
              Case 77
                ControlerEvent$ = "Sound Control 3: "+Str(MValue)
              Case 78
                ControlerEvent$ = "Sound Control 4: "+Str(MValue)
              Case 79
                ControlerEvent$ = "Sound Control 5: "+Str(MValue)
              Case 80
                ControlerEvent$ = "General Purpose Button1: "
                If MValue >0 And MValue<64
                  ControlerEvent$+"On"
                Else
                  ControlerEvent$+"Off"
                EndIf
              Case 81
                ControlerEvent$ = "General Purpose Button2: "
                If MValue >0 And MValue<64
                  ControlerEvent$+"On"
                Else
                  ControlerEvent$+"Off"
                EndIf
              Case 82
                ControlerEvent$ = "General Purpose Button3: "
                If MValue >0 And MValue<64
                  ControlerEvent$+"On"
                Else
                  ControlerEvent$+"Off"
                EndIf
              Case 83
                ControlerEvent$ = "General Purpose Button4: "
                If MValue >0 And MValue<64
                  ControlerEvent$+"On"
                Else
                  ControlerEvent$+"Off"
                EndIf
              Case 91
                ControlerEvent$ = "Effects Level: "+Str(MValue)
              Case 92
                ControlerEvent$ = "Tremolo Level: "+Str(MValue)
              Case 93
                ControlerEvent$ = "Chorus Level: "+Str(MValue)
              Case 94
                ControlerEvent$ = "Celeste Level: "+Str(MValue)
              Case 95
                ControlerEvent$ = "Phaser Level: "+Str(MValue)
              Case 96
                ControlerEvent$ = "Data Button Increment"
              Case 97
                ControlerEvent$ = "Data Button Decrement"
              Case 99
                ControlerEvent$ = "Non-Registered Parameter Number - Coarse: "+Str(MValue)
              Case 98
                ControlerEvent$ = "Non-Registered Parameter Number - Fine: "+Str(MValue)
              Case 101
                ControlerEvent$ = "Registered Parameter Number - Coarse: "+Str(MValue)
              Case 100
                ControlerEvent$ = "Registered Parameter Number - Fine: "+Str(MValue)
              Case 120
                ControlerEvent$ = "All Sound Off"
              Case 121
                ControlerEvent$ = "All Controllers Off"
              Case 122
                ControlerEvent$ = "Local Keyboard: "
                If MValue >0 And MValue<64
                  ControlerEvent$+"On"
                Else
                  ControlerEvent$+"Off"
                EndIf
              Case 123
                ControlerEvent$ = "All Notes Off"
              Case 124
                ControlerEvent$ = "Omni Off"
              Case 125
                ControlerEvent$ = "Omni On"
              Case 126
                ControlerEvent$ = "Monophonic Mode"+Str(MValue)
              Case 127
                ControlerEvent$ = "Polyphonic Mode"+Str(MValue)
              Default 
                ControlerEvent$ = "Unknown Controler Number: "+Str(MControlerNumber)+" - Value = "+Str(MValue)
            EndSelect
            MidiEvent$ ="Controller, channel "+Str(TEvent&$F)+" - "+ControlerEvent$
                
          ElseIf TEvent >=$C0 And TEvent <=$CF
            MProgramNumber = ReadByte() : If MProgramNumber <0 : MProgramNumber + 256 : EndIf
            MidiEvent$ ="Program Change, channel "+Str(TEvent&$F)+" - ProgramNumber : "+Str(MProgramNumber)+" : "+MidiInstrument$(MProgramNumber)
          ElseIf TEvent >=$D0 And TEvent <=$DF
            MPressure = ReadByte() : If MPressure <0 : MPressure + 256 : EndIf
            MidiEvent$ ="ChannelPressure, channel "+Str(TEvent&$F)+" - Pressure : "+Str(MPressure)
          ElseIf TEvent >=$E0 And TEvent <=$EF
            MPitch = ReadByte() : If MPitch<0 : MPitch+256 : EndIf
            MPitch<<7
            MPitch = ReadByte() + MPitch - $2000
            MidiEvent$ ="PitchWheel, channel "+Str(TEvent&$F)+" - Pitch : "+Str(MPitch)
          ElseIf TEvent =$F1
            MTimeCode = ReadByte()
            MidiEvent$ ="MTC : "+Str(MTimeCode)
          ElseIf TEvent =$F2
            MBeat = ReadByte() : If MBeat <0 : MBeat +256 : EndIf
            MBeat <<7
            MBeat = ReadByte() + MBeat
            MidiEvent$ ="Midi Beat : "+Str(MBeat)
          ElseIf TEvent =$F3
            MNumber = ReadByte()
            MidiEvent$ ="SongSelect : "+Str(MNumber)
          ElseIf TEvent =$F6
            MidiEvent$ ="TuneRequest"
          ElseIf TEvent =$F8
            MidiEvent$ ="MidiClock"
          ElseIf TEvent =$F9
            MidiEvent$ ="MidiTick"
          ElseIf TEvent =$FA
            MidiEvent$ ="MidiStart"
          ElseIf TEvent =$FC
            MidiEvent$ ="MidiStop"
          ElseIf TEvent =$FB
            MidiEvent$ ="MidiCOntinue"
          ElseIf TEvent =$FE
            MidiEvent$ ="ActivSens"
          ElseIf TEvent =$FF
            MidiEvent$ ="Reset"
          Else
            MidiEvent$ ="Unknown Event: "+Hex(TEvent)
            ReadVLD ()
          EndIf
          Debug Str(Delta_time)+": "+MidiEvent$
        EndIf
        Wend
      EndIf
    Wend
      
    CloseFile(0)
  EndIf
EndProcedure
;
Procedure.s ReadStringl(Length.l)
; by Zapman
; (Read string Length from file)
; Lit "Length" caractères dans le fichier actuellement ouvert et retourne le résultat
; sous forme d'une chaine de caractere

; Read "Length" caracteres from the open file and return the result
; as a string.
  compt.l=0
  s$=""
  While compt<Length
    b=ReadByte()
    s$=s$+Chr(b)
    compt + 1
  Wend
  ProcedureReturn s$
EndProcedure
;
Procedure VLDToNum (v) ; Variable lenght Datas decoder
  v&$7F7F7F7F
  rv = 0
  ct = 0
  While v
    l1 = v&$FF
    ct2 = ct : While ct2 : l1*$80 : ct2 - 1 : Wend
    rv + l1
    v /256
    ct + 1
  Wend
  ProcedureReturn rv
EndProcedure
;
Procedure ReadVLD ()
  v = 0
  Repeat
    d.b = ReadByte()
    v<<8
    v | d
  Until d&$80 = 0
  ProcedureReturn VLDToNum (v)
EndProcedure
;
;
; ******************* BONUS *******************
; 
; If you want to create your own MIDI Files
; you will need that :
;
;
Procedure NumToVLD (v) ; Variable lenght Datas encoder
  ct = 0
  rv = 0
  While v
    l1 = v&$7F
    v = (v - l1)/$80
    If ct > 0
      l1+ $80
    EndIf
    ct2 = ct : While ct2 : l1*256 : ct2 - 1 : Wend
    rv + l1
    ct + 1
  Wend
  ProcedureReturn rv
EndProcedure
;
Procedure WriteVLD (v)
  vo = NumToVLD (v)
  ct = 3
  While PeekB(@vo+ct)=0 : ct - 1 : Wend
  While ct>=0
    v = PeekB(@vo+ct) : If v<0 : v + 256 : EndIf
    WriteByte(v)
    ct - 1
  Wend
EndProcedure 


;

DataSection
SMI:
  Data.s "Ac Gd Piano"
  Data.s "Bght Ac Piano"
  Data$ "El Gd Piano"
  Data$ "Honky-tonk Piano"
  Data$ "Electric Piano 1"
  Data$ "Electric Piano 2"
  Data$ "Harpsichord"
  Data$ "Clavi"
  Data$ "Celesta"
  Data$ "Glockenspiel"
  Data$ "Music Box"
  Data$ "Vibraphone"
  Data$ "Marimba"
  Data$ "Xylophone"
  Data$ "Tubular Bells"
  Data$ "Dulcimer" 
  Data$ "Drawbar Organ" 
  Data$ "Percussive Organ" 
  Data$ "Rock Organ" 
  Data$ "Church Organ" 
  Data$ "Reed Organ" 
  Data$ "Accordion" 
  Data$ "Harmonica" 
  Data$ "Tango Accordion" 
  Data$ "Ac Guitar (nylon)" 
  Data$ "Ac Guitar (steel)" 
  Data$ "El Guitar (jazz)" 
  Data$ "El Guitar (clean)" 
  Data$ "El Guitar (muted)" 
  Data$ "Overdrive Guitar" 
  Data$ "Distortion Guitar" 
  Data$ "Guitar harmonic" 
  Data$ "Ac Bass" 
  Data$ "El Bass (finger)" 
  Data$ "El Bass (pick)" 
  Data$ "Fretless Bass" 
  Data$ "Slap Bass 1" 
  Data$ "Slap Bass 2" 
  Data$ "Synth Bass 1" 
  Data$ "Synth Bass 2" 
  Data$ "Violin" 
  Data$ "Viola" 
  Data$ "Cello" 
  Data$ "Contrabasse" 
  Data$ "Tremolo Strings" 
  Data$ "Pizzicato Strings" 
  Data$ "Orchestral Harp" 
  Data$ "Timpani" 
  Data$ "String Ensemble 1" 
  Data$ "String Ensemble 2" 
  Data$ "SynthStrings 1" 
  Data$ "SynthStrings 2" 
  Data$ "Choir Aahs" 
  Data$ "Voice Oohs" 
  Data$ "Synth Voice" 
  Data$ "Orchestra Hit" 
  Data$ "Trumpet" 
  Data$ "Trombone" 
  Data$ "Tuba" 
  Data$ "Muted Trumpet" 
  Data$ "French Horn" 
  Data$ "Brass Section"
  Data$ "SynthBrass 1" 
  Data$ "SynthBrass 2" 
  Data$ "Soprano Sax" 
  Data$ "Alto Sax" 
  Data$ "Tenor Sax" 
  Data$ "Baritone Sax" 
  Data$ "Oboe" 
  Data$ "English Horn" 
  Data$ "Bassoon" 
  Data$ "Clarinet" 
  Data$ "Piccolo" 
  Data$ "Flute" 
  Data$ "Recorder" 
  Data$ "Pan Flute"
  Data$ "Blown Bottle" 
  Data$ "Shakuhachi" 
  Data$ "Whistle" 
  Data$ "Ocarina" 
  Data$ "Lead 1 (square)" 
  Data$ "Lead 2 (sawtooth)" 
  Data$ "Lead 3 (calliope)" 
  Data$ "Lead 4 (chiff)" 
  Data$ "Lead 5" 
  Data$ "Lead 6 (voice)" 
  Data$ "Lead 7 (fifths)" 
  Data$ "Lead 8 (bass + lead)" 
  Data$ "Pad 1 (new age)"
  Data$ "Pad 2 (warm)" 
  Data$ "Pad 3 (polysynth)" 
  Data$ "Pad 4 (choir)" 
  Data$ "Pad 5 (bowed" 
  Data$ "Pad 6 (metallic)" 
  Data$ "Pad 7 (halo)" 
  Data$ "Pad 8 (sweep)" 
  Data$ "FX 1 (rain)" 
  Data$ "FX 2 (soundtrack)" 
  Data$ "FX 3 (crystal)" 
  Data$ "FX 4 (atmosphere)" 
  Data$ "FX 5 (brightness)" 
  Data$ "FX 6 (goblins)" 
  Data$ "FX 7 (echoe)" 
  Data$ "FX 8 (sci-fi)" 
  Data$ "Sitar" 
  Data$ "Banjo" 
  Data$ "Shamisen" 
  Data$ "Koto" 
  Data$ "Kalimba" 
  Data$ "Bag pipe" 
  Data$ "Fiddle" 
  Data$ "Shanai" 
  Data$ "Tinkle Bell" 
  Data$ "Agogo" 
  Data$ "Steel Drums" 
  Data$ "Woodblock" 
  Data$ "Taiko Drum" 
  Data$ "Melodic Tom" 
  Data$ "Synth Drum" 
  Data$ "Reverse Cymba"
  Data$ "Guitar Fret Noise" 
  Data$ "Breath Noise" 
  Data$ "Seashore"
  Data$ "Bird Tweet" 
  Data$ "Telephone Ring" 
  Data$ "Helicopter"
  Data$ "Applause"
  Data$ "Gunshot"
EndDataSection

Last edited by zapman* on Sun Oct 17, 2004 12:01 pm, edited 4 times in total.
Don't try - DO it !
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post by einander »

Very good, Zapman: Works nice!

At the end of some MIDIfiles, appears the message Abnormal EndOfFile Encountered, but the MIDIfiles are OK.
Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post by Dare2 »

Very nice.

With some midi files, appears to get stuck in a loop on Note Off. (Is it intended for only some midi types?)

BTW, a great site for midi format info is:

http://www.borg.com/~jglatt/
@}--`--,-- A rose by any other name ..
eriansa
Enthusiast
Enthusiast
Posts: 277
Joined: Wed Mar 17, 2004 12:31 am
Contact:

Post by eriansa »

With some midi files, appears to get stuck in a loop on Note Off. (Is it intended for only some midi types?)

Same here...looks like it gets stuck on a tempo track.

Btw Zapman : how is your drag and drop going in your audio editor? If you want I can send you a (very small but handy) C++ DLL to solve the problem.

c ya.
zapman*
Enthusiast
Enthusiast
Posts: 115
Joined: Wed Jun 02, 2004 10:17 pm
Location: New Caledonia (South Pacific)
Contact:

Post by zapman* »

I made some changes to the code given in the top of this post.

Could you please test this new version and give me a feedback ? I you have still problems, thank you to send me your Mid file at :
seproject@freesoundeditor.com

@eriansa : could you send me your C++ code ? It would be marvelous !
Don't try - DO it !
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post by einander »

Hi Zapman: Very good work!

I've found strange values on some DeltaTimes:

268419402: Note On, channel 2 - Note : 67 - Velocity : 100
120: Note Off, channel 2 - Note : 67 - Velocity : 0

Here is a thread with VarLen and LenVar ASM procedures by Pychophanta.
viewtopic.php?t=8639&highlight=deltatime
Are you planning to do a PB MIDI player?
Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post by Dare2 »

Hi zapman*,

That cured the loops! Haven't checked in as much detail as einander has, but this is great!

(PS: I spent several days trying to do something similar (a while back) and couldn't get the timing right. Your code will, I hope, show me the error of my ways).

Thanks :)
@}--`--,-- A rose by any other name ..
zapman*
Enthusiast
Enthusiast
Posts: 115
Joined: Wed Jun 02, 2004 10:17 pm
Location: New Caledonia (South Pacific)
Contact:

Post by zapman* »

Thank you for your tests. einander is right : there is still a problem in the computing of the delta time. I will let you know when I find that.
einander wrote:Are you planning to do a PB MIDI player?
Yes, a partition editor. But it will play from wave sounds. It's called MonPiano.
Image
Don't try - DO it !
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post by einander »

@Zapman:
On your Meta-events list is missing (intentionally?)

Code: Select all

Case $21
MetaEvent$="MIDI Port"
MMA never endorsed their use, and www.borg.com says it is obsolete, but I've found it in many midifiles made by CubaseVST and CakeWalk.
zapman*
Enthusiast
Enthusiast
Posts: 115
Joined: Wed Jun 02, 2004 10:17 pm
Location: New Caledonia (South Pacific)
Contact:

Post by zapman* »

Thank you very much. I did'nt know what this code means. I'll add it.
Don't try - DO it !
zapman*
Enthusiast
Enthusiast
Posts: 115
Joined: Wed Jun 02, 2004 10:17 pm
Location: New Caledonia (South Pacific)
Contact:

Post by zapman* »

I made a last correction to the code to solve the ReadVLD () problem. Now, it seems to work perfectly. I have just replaced
d = ReadByte()
by
d.b = ReadByte()
and it's OK.
I you find anything else, please repport.
Thanks again for your help.
Don't try - DO it !
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post by einander »

Now the Delta-times seems to work OK! :P
ricardo
Addict
Addict
Posts: 2438
Joined: Fri Apr 25, 2003 7:06 pm
Location: Argentina

Post by ricardo »

Where can i see if each note is a quarter, etc or the time duration of each note?
ARGENTINA WORLD CHAMPION
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post by einander »

@Ricardo:
note lenghts are not explicit on a MIDIfile. You must calculate the lenghts from each note's start and end positions, stored on the MIDIfile as variable length quantities.
This process (a little complicated) is the core of any MIDIparser.
Here is a very complete MIDI tutorial.
Have fun!
Tyr
New User
New User
Posts: 4
Joined: Tue Oct 11, 2005 10:35 pm

Post by Tyr »

Well, I`ve been looking at this Code for Days now and I still do not know what to do with it. First of all:

How do I find out the Startingposition of an Event? Seems to have something to do with that Deltatimes. But the Deltatime doen`t seem to be in the format like: the Event occurs at Point x after the Beginning of the Song (or maybe I`m wrong?) and what has the Deltatime Increment to do with it? How do I find out the position of, let`s say a marker? How is the Time Snigature calculated? Where is the Tempo stored? How do I know how long a MidiTick is? Over and over: Timing Questions. Well the rest seems to be pretty clear. "Note" means the number of the Note from 0-127, Velocity is the strenght or loudness of the played note (also from 0 to 127). The rest seems to be Controler or Meta Events. (Beside, how can I find out the Content of an Meta Event? The Code looks like that it only recognizes if it is, let`s say, a Metaevent is a lyric Event or not, but not witch Lyric was set.)

Well, of course I found some Pages on the Web concerning the Midi and the SMF Standard, but they weren`t very, well enlightning to me.

Probably you both could give me some hints for I`m more a muscian than a programmer (that`s why I came to Purebasic, it`s easy to understand), and the Midi Standard always looked very simpel and logical to me. But while I`m trying to decode this decoder, there`s a voice in me witch says: "A Audio stream is much easier to handle." Maybe I`m wrong, but this is heavy stuff for me.

I`m grapefull for any help

Tier
Post Reply