Sending MIDI Data

Just starting out? Need help? Post your questions and find answers here.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Stan.

Hi,

I am a complete newbie at PB, and would appreciate any help dealing
with sending MIDI commands from PB ( I am trying to make a semi-random
composer for my MIDI racks, kind of poor man's Max or (Korg) Karma thing ).

TIA.



Learning and Love are what life is all about ... [ PB. registered user ]
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by ricardo.
Hi,

I am a complete newbie at PB, and would appreciate any help dealing
with sending MIDI commands from PB ( I am trying to make a semi-random
composer for my MIDI racks, kind of poor man's Max or (Korg) Karma thing ).
WillinYork has a very nice MIDI app, contact him or follow his post in the forum : )
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Stan.
Hi,

I am a complete newbie at PB, and would appreciate any help dealing
with sending MIDI commands from PB ( I am trying to make a semi-random
composer for my MIDI racks, kind of poor man's Max or (Korg) Karma thing ).

TIA.
Hi,

Here is what you need :

=====================================================================
; Simple MIDI messages access
;
; Copyright 02/2002 by Stan a.k.a [url]mailto:Daniel-Marc.Ducros@lcpc.fr">Daniel-Marc.Ducros@lcpc.fr
;
; Credits :
;
; - ALL DLL INTERFACE PROVIDED BY Mr. SKUNKS
;

Procedure.s Get_Dev_Caps( Device_Num.l, *Cap_Pointer.MIDIOUTCAPS, Cap_Size.l )
CallDLL3( 4, Device_Num, *Cap_Pointer, Cap_Size )
n.w = DLLNum( )
name_string.s = " "
If n = 0
j = 0
While *Cap_Pointer\szPname[j]
PokeB( @name_string+j, *Cap_Pointer\szPname[j] )
j = j + 1
Wend
PokeB( @name_string+j, *Cap_Pointer\szPname[j] )
EndIf
ProcedureReturn name_string
EndProcedure

; Opens the MIDI device and return a pointer to it in

Procedure.w Midi_Out_Open( *Device_Pointer.l, Dev_Num.l )
Null.l = 0
CallDLL5( 1, *Device_Pointer, Dev_Num, Null, Null, Null ) ; No CallBack ...
ProcedureReturn DLLNum( )
EndProcedure

; Closes the MIDI device

Procedure.w Midi_Out_Close( Midi_Device.l )
CallDLL1( 2, Midi_Device )
ProcedureReturn DLLNum( )
EndProcedure

; Changes sound ( GM set only )
;

Procedure.w Change_Sound( Sound.b, Channel.b, *Midi_Device.l )
Zp.l = 0
PokeB( ( @Zp ) + 1, Sound ) ; New sound number ( see a GM synth doc )
PokeB( ( @Zp ) + 0, $Bf + Channel ) ; MIDI Change program message ( n = MIDI Channel - 1 )
CallDLL2( 3, *Midi_Device, Zp ) ; Send the whole shebang !
ProcedureReturn DLLNum( )
EndProcedure

; Begins to play Note , with a velocity , on MIDI Channel
; on MIDI device pointed by

Procedure.w Note_On( Note.b, Vel.b, Channel.b, Midi_Device.l )
Zp.l = 0
PokeB( ( @Zp ) + 2, Vel ) ; Velocity 0 = NoteOff ( on most Synths ) 64 = mp, 127 = ff
PokeB( ( @Zp ) + 1, Note ) ; Note 0 = C-2 127 = G8 ( Depending on synth ... )
PokeB( ( @Zp ) + 0, $8f + Channel ) ; MIDI Note On Msg 0x9n ( n = MIDI Channel - 1 )
CallDLL2( 3, Midi_Device, Zp ) ; Send the whole shebang !
ProcedureReturn DLLNum( )
EndProcedure

; Stop Note , with a velocity , on MIDI Channel
; on MIDI device pointed by

Procedure.w Note_Off( Note.b, Vel.b, Channel.b, Midi_Device.l )
Zp.l = 0
PokeB( ( @Zp ) + 2, Vel ) ; Velocity ( Depends on Synth ... Most don't use it ... )
PokeB( ( @Zp ) + 1, Note ) ; Note 0 = C-2 127 = G8 ( Depending on synth ... )
PokeB( ( @Zp ) + 0, $7f + Channel ) ; MIDI Note Off Msg 0x8n ( n = MIDI Channel - 1 )
CallDLL2( 3, Midi_Device, Zp ) ; Send the whole shebang !
ProcedureReturn DLLNum( )
EndProcedure

N.w = Get_Num_Devs( )

For Midi_Dev.l = -1 To N - 1 ; -1 = "Magic" value !!! ( Microsoft MIDI Mapper )
PrintN( Get_Dev_Caps( Midi_Dev, @midicap, Cap_Size.l ) ) ; Get device properties and print name
Midi_Out_Open( @Device_Pointer, Midi_Dev ) ; Open device
Note.b = 48
Vel.b = 40
Chan.b = 1
Sound.b = 0
For ii = 0 To 4 ; Make some noise
Change_Sound( Sound, Chan, Device_Pointer ) ; Select sound
Note_On( Note, Vel, Chan, Device_Pointer ) ; Play 1 note
Delay( 500 ) ; Wait a bit
Note_Off( Note, Vel, Chan, Device_Pointer ) ; Stop note
Note = Note + 12 ; 1 octave up
Vel = Vel + 20 ; Strike harder next time
Sound = Sound + 10
Next ii
Midi_Out_Close( Device_Pointer )
Next Midi_Dev
=====================================================================

This works under 98SE, could people with other OS ( W2000, XP ... ),
let me know if it still work for them ?

TIA



Learning and Love are what life is all about ... [ PB. registered user ]
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by El_Choni.

Hi,

Thanks for your code! Anyway, I had to change the following lines to avoid Windows crash (page fault at Kernel32.dll, etc.) after showing Midi Mapper:

Code: Select all

Procedure.s Get_Dev_Caps(Device_Num.l, *Cap_Pointer.MIDIOUTCAPS, Cap_Size.l) 
  CallDLL3(4, Device_Num, *Cap_Pointer, Cap_Size)
  n.w = DLLNum( )
  name_string.s = " "
  If n = 0
    j = 0
    While *Cap_Pointer\szPname[j]
      PokeB(@name_string+j, *Cap_Pointer\szPname[j])
      j = j + 1
    Wend
    PokeB( @name_string+j, *Cap_Pointer\szPname[j] )
  EndIf
  ProcedureReturn name_string 
EndProcedure
For this one:

Code: Select all

Procedure.s Get_Dev_Caps(Device_Num.l, *Cap_Pointer.MIDIOUTCAPS, Cap_Size.l)
  CallDLL3(4, Device_Num, *Cap_Pointer, Cap_Size)
  n.w = DLLNum()
  name_string.s = " "
  If n = 0
    name_string = PeekS(@*Cap_Pointer\szPname[0])
  EndIf 
  ProcedureReturn name_string
EndProcedure
Don't ask me why I did it this way, just figured out what was going on in the proc and substituted it for something less 'C like' (* reminds me of C, horror).

Did anybody else have this problem? Bye,


El_Choni
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by fred.
; Ultimate word : Don't tell me this code is not the best one, I am just a C programmer ...
No problem about it :). Just an advice: try to use a structure when possible instead of ugly pokes..

For Example:

Structure MidiControl
Channel.b
Note.b
Velocity.b
EndStructure

Zp.MidiControl\Velocity = Vel
Zp\Note = Note
Zp\Channel = $7f+Channel

Could replace the three following lines (note than the structure need to be declared once at programme top):

PokeB( ( @Zp ) + 2, Vel )
PokeB( ( @Zp ) + 1, Note )
PokeB( ( @Zp ) + 0, $7f + Channel)

It's easier to read, faster and smaller (in exec size). Thanks for your nice MIDI example.


Fred - AlphaSND
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by MrVainSCL.

Hi Stan!
Nice example you posted! Have someone a working example how to play/stop/loop MidiFiles, using complete API commands instead to use the MovieLib? :wink: Thanks in advance...



PIII450, 256MB Ram, 6GB HD, RivaTNT, DirectX8.1, SB AWE64, Win98SE + Updates...

greetz
MrVainSCL! aka Thorsten
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Paul.

I would do it this way...
(and my version doesn't require anyone to send me anything) :)

Code: Select all

Structure MIDIDATA
  Channel.b
  Note.b
  Velocity.b
  Null.b
EndStructure
 
midi.MIDIOUTCAPS
devices=midiOutGetNumDevs_()
For devnum=-1 To devices-1
  If midiOutGetDevCaps_(devnum,@midi,SizeOf(MIDIOUTCAPS))=0
    If midi\wVoices>0
      midiport=devnum
    EndIf
  EndIf
Next 
 
*hMidiOut.l
result=midiOutOpen_(@hMidiOut,midiport,0,0,0)
 
Note.b=48
Vel.b=127
Channel.b=1
Instrument.b=1
 
dMsg.MIDIDATA\Note=Instrument
dMsg\Channel=$bf+Channel
result=midiOutShortMsg_(hMidiOut,PeekW(dMsg))
 
For x=1 To 30
  dMsg\Velocity=Vel
  dMsg\Note=Note
  dMsg\Channel=$8f+Channel
  result=midiOutShortMsg_(hMidiOut,PeekL(dMsg))
  Delay(50)
  dMsg\Channel=$7f+Channel
  result=midiOutShortMsg_(hMidiOut,PeekL(dMsg))
  Note+2
Next 
 
result=midiOutClose_(hMidiOut)




Edited by - paul on 13 February 2002 23:45:55
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by MrVainSCL.

Hi Paul!
Very nice and small example source! That is what i would call a optimized code! I tested your example and there is a very small mistake/error... Here is the correct working version of Paul´s example:

Code: Select all

    Structure MIDIDATA
      Channel.b
      Note.b
      Velocity.b
      Null.b
    EndStructure
    ;
    midi.MIDIOUTCAPS
    devices=midiOutGetNumDevs_()
    ;
    For devnum=-1 To devices-1
      If midiOutGetDevCaps_(devnum,@midi,SizeOf (MIDIOUTCAPS))=0
        If midi\wVoices>0
          midiport=devnum
        EndIf
      EndIf
    Next 
    ;
    *hMidiOut.l
    result=midiOutOpen_(@hMidiOut,midiport,0,0,0)
    ;
    Note.b       = 48
    Vel.b        = 127
    Channel.b    = 1
    Instrument.b = 1
    ;
    dMsg.MIDIDATA\Note=Instrument
    dMsg\Channel=$bf+Channel
    result=midiOutShortMsg_(hMidiOut,PeekW(dMsg))
    ;
    For x=1 To 30
      dMsg\Velocity=Vel
      dMsg\Note=Note
      dMsg\Channel=$8f+Channel
      result=midiOutShortMsg_(hMidiOut,PeekL(dMsg))
      Sleep_(50)
      dMsg\Channel=$7f+Channel
      result=midiOutShortMsg_(hMidiOut,PeekW(dMsg))
      Note+2
    Next 
    ;
    result=midiOutClose_(hMidiOut)

PIII450, 256MB Ram, 6GB HD, RivaTNT, DirectX8.1, SB AWE64, Win98SE + Updates...

greetz
MrVainSCL! aka Thorsten


Edited by - MrVainSCL on 13 February 2002 23:45:19
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Paul.

It looks like all you changed was
Delay(50) to Sleep_(50)
Which of course works fine either way :)

What you forgot to correct was the second PeekW() should be PeekL()
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by MrVainSCL.
Edited by - paul on 13 February 2002 23:45:55
hehe... Paul, that is what i call fast online fix/update - cool!

PIII450, 256MB Ram, 6GB HD, RivaTNT, DirectX8.1, SB AWE64, Win98SE + Updates...

greetz
MrVainSCL! aka Thorsten
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Paul.

hehe
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by MrVainSCL.
It looks like all you changed was
Delay(50) to Sleep_(50)
Which of course works fine either way :)

What you forgot to correct was the second PeekW() should be PeekL()
Good morning Paul! :wink:
No no... in your first posting there was following codeline:
  • If midiOutGetDevCaps_(devnum,@midi,SizeOf To:devnum,@midi,SizeOf>(MIDIOUTCAPS))=0
    • I corrected only this small mistake and changed Delay() to Sleep_() - right!
      Btw have a look to the time when we have posted the stuff *lool* - Stay cool...


      PIII450, 256MB Ram, 6GB HD, RivaTNT, DirectX8.1, SB AWE64, Win98SE + Updates...

      greetz
      MrVainSCL! aka Thorsten
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Paul.

Hello MrVainSCL...

I really can't see what you are trying to correct??
I think the Forum is maybe messing things up because your code seems to have links in it.

Are you trying to put a

Code: Select all

>
(greater than sign) in?
If so, why?


Oh well.



Edited by - paul on 14 February 2002 00:13:30
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by MrVainSCL.
I really can't see what you are trying to correct??
I think the Forum is maybe messing things up because your code seems to have links in it.

Are you trying to put a

Code: Select all

>
(greater than sign) in?
If so, why?
Mhhhh its ok... i have copy paste your example with a link in it and so i corrected it... I dont have added the greater than sign... Let us forget this... your source is now working fine... :wink: bye


PIII450, 256MB Ram, 6GB HD, RivaTNT, DirectX8.1, SB AWE64, Win98SE + Updates...

greetz
MrVainSCL! aka Thorsten
Post Reply