Sending MIDI Data
- 
				BackupUser
- PureBasic Guru 
- Posts: 16777133
- Joined: Tue Apr 22, 2003 7:42 pm
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 ]
			
			
									
									
						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 
- Posts: 16777133
- Joined: Tue Apr 22, 2003 7:42 pm
Restored from previous forum. Originally posted by ricardo.
 
			
			
									
									
						WillinYork has a very nice MIDI app, contact him or follow his post in the forum : )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 ).
- 
				BackupUser
- PureBasic Guru 
- Posts: 16777133
- Joined: Tue Apr 22, 2003 7:42 pm
Restored from previous forum. Originally posted by Stan.
 
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 ]
			
			
									
									
						Hi,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.
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 
- Posts: 16777133
- Joined: Tue Apr 22, 2003 7:42 pm
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:
For this one:
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
			
			
									
									
						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
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
Did anybody else have this problem? Bye,
El_Choni
- 
				BackupUser
- PureBasic Guru 
- Posts: 16777133
- Joined: Tue Apr 22, 2003 7:42 pm
Restored from previous forum. Originally posted by fred.
  . Just an advice: try to use a structure when possible instead of ugly pokes..
. 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
			
			
									
									
						No problem about it; Ultimate word : Don't tell me this code is not the best one, I am just a C programmer ...
 . Just an advice: try to use a structure when possible instead of ugly pokes..
. 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 
- Posts: 16777133
- Joined: Tue Apr 22, 2003 7:42 pm
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? Thanks in advance...
 Thanks in advance...
PIII450, 256MB Ram, 6GB HD, RivaTNT, DirectX8.1, SB AWE64, Win98SE + Updates...
greetz
MrVainSCL! aka Thorsten
			
			
									
									
						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?
 Thanks in advance...
 Thanks in advance...PIII450, 256MB Ram, 6GB HD, RivaTNT, DirectX8.1, SB AWE64, Win98SE + Updates...
greetz
MrVainSCL! aka Thorsten
- 
				BackupUser
- PureBasic Guru 
- Posts: 16777133
- Joined: Tue Apr 22, 2003 7:42 pm
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)
Edited by - paul on 13 February 2002 23:45:55
			
			
									
									
						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 
- Posts: 16777133
- Joined: Tue Apr 22, 2003 7:42 pm
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:
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
			
			
									
									
						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 
- Posts: 16777133
- Joined: Tue Apr 22, 2003 7:42 pm
- 
				BackupUser
- PureBasic Guru 
- Posts: 16777133
- Joined: Tue Apr 22, 2003 7:42 pm
- 
				BackupUser
- PureBasic Guru 
- Posts: 16777133
- Joined: Tue Apr 22, 2003 7:42 pm
- 
				BackupUser
- PureBasic Guru 
- Posts: 16777133
- Joined: Tue Apr 22, 2003 7:42 pm
Restored from previous forum. Originally posted by MrVainSCL.
 
No no... in your first posting there was following codeline:
			
			
									
									
						Good morning 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()

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
 
- I corrected only this small mistake and changed Delay() to Sleep_() - right! 
- 
				BackupUser
- PureBasic Guru 
- Posts: 16777133
- Joined: Tue Apr 22, 2003 7:42 pm
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 (greater than sign) in?
If so, why?
Oh well.
Edited by - paul on 14 February 2002 00:13:30
			
			
									
									
						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
>If so, why?
Oh well.
Edited by - paul on 14 February 2002 00:13:30
- 
				BackupUser
- PureBasic Guru 
- Posts: 16777133
- Joined: Tue Apr 22, 2003 7:42 pm
Restored from previous forum. Originally posted by MrVainSCL.
  bye
 bye
PIII450, 256MB Ram, 6GB HD, RivaTNT, DirectX8.1, SB AWE64, Win98SE + Updates...
greetz
MrVainSCL! aka Thorsten
			
			
									
									
						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...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(greater than sign) in?Code: Select all
>
If so, why?
 bye
 byePIII450, 256MB Ram, 6GB HD, RivaTNT, DirectX8.1, SB AWE64, Win98SE + Updates...
greetz
MrVainSCL! aka Thorsten