Hi,
does anyone know how to play midi notes using the functions midiOutOpen, midiOutSetVolume, midiOutShortMsg and midiOutClose of "user32.dll" ?
The mididemo source of EBasic is too complicated for me ! :-[
Thank you !
Hi!
You can find other and easier to use samples in order to learn how to play midi notes.
Here is what i got from the users guide and it's quite easy to understand after reading the "music and sound" chapter of the users guide.
OPENCONSOLE
pThread = PLAYMIDI$( "T180 N0 I0 O5 C8C#DD#EFF#GG#AA#B O6 CC#DD#EFF#GG#AA#B O7 C1", TRUE )
DO:UNTIL INKEY$ <> ""
STOPMIDI$(pThread)
PLAYMIDI$ "T120 N0 I25 O5 *C2EG;D4EFG*A2O6CE; *C2EG;D4EFG*A2O7CE;"
Additional samples :
PLAYMIDI$("N0 O6 V64 I0 T80 C8 T120 C8 D4 CF T80 E4 R8 C8 T120 C8 D4 CG T80 F4 R8 C8 T120 C8 O7 C4 O6 AFE T80 D4 R8 A#8 T120 A#8 A4 FGF2")
'REQUIRES IBasic Pro
'Steve Boothman aka Bevets and ibDevGroup September 2004
autodefine "off"
DECLARE "user32.dll",LoadCursorA(hInstance:INT,lpCursorName:INT),INT
DECLARE "user32.dll",GetDlgCtrlID(hwnd:INT),INT
DECLARE "user32.dll",GetWindowTextA(hwnd:INT,lpSTRING:STRING,cch:INT),INT
DECLARE "user32.dll",GetSysColor(nIndex:INT),INT
CONST WM_SETCURSOR = 0x20
CONST IDC_HAND = 32649
TYPE note
def key:Int
def note:String
def duration:String
def rest:String
ENDTYPE
Def NOTEVOLUME,CHANNEL,INSTRUMENT,TEMPO:Int
def oldnote,note,res,run:int
def l,t,c,x,z,offset,keyoffset,buttonoffset:int
def key,oldkey,slide,record,ti,tie,count,pboffset,Abort:Int
def Wnd,WhiteW[29],BlackW[20]:window
Def mypointer,temp,pos:pointer
Def pThread:POINTER
Def White[29],Black[20],bp[20]:Int
Def wkeys[7],bkeys[7],voice[129]:String
def thisnote:String
bp[0]=15,39,87,111,135,183,207,255,279,303,351,375,423,447,471,519,543,591,615,639
White[0]=48,50,52,53,55,57,59,60,62,64,65,67,69,71,72,74,76,77,79,81,83,84,86,88,89,91,93,95,96
Black[0]=49,51,54,56,58,61,63,66,68,70,73,75,78,80,82,85,87,90,92,94
wkeys[0]="A","B","C","D","E","F","G"
bkeys[0]="A","C","D","F","G"
buttonoffset=7
pboffset=0
Gosub AddVoices
l=1:c=2
NOTEVOLUME = 127 :'max is 127
TEMPO=120
CHANNEL=0
INSTRUMENT=21
openwindow Wnd,0,0,800,204,@sysmenu|@caption|@border,0,"",&WndProc
'create black keys first so that they stay on top
For t = 0 To 19
openwindow BlackW[t],bp[t],24,15,75,@NOCAPTION|@NOAUTODRAW,Wnd,"",&WndProc
CONTROL BlackW[t],@BUTTON,"#"+chr$(13)+bkeys[l],0,0,16,75,0x50002000,Black[t]
SetControlColor BlackW[t],Black[t],RGB(255,255,255),RGB(0,0,0)
l++:c++:If l = 5 Then l = 0
Next t
l=0:c=2
For t = 0 To 28
openwindow WhiteW[t],l,24,24,120,@NOCAPTION|@NOAUTODRAW,Wnd,"",&WndProc
CONTROL WhiteW[t],@BUTTON,chr$(13)+chr$(13)+chr$(13)+wkeys[c],0,0,24,120,0x50002000,White[t]
SetControlColor WhiteW[t],White[t],RGB(0,0,0),RGB(255,255,255)
l=l+24:c++:If c = 7 Then c = 0
Next t
SetControlColor WhiteW[7],White[7],RGB(0,0,0),RGB(255,240,255)
gosub AddButtonKeys
gosub FinishInit
run=1
waituntil run=0
ListRemoveAll(mypointer,TRUE)
closewindow Wnd
SUB WndProc
select @CLASS
CASE WM_SETCURSOR
SetCursor Wnd,@CSCustom,LoadCursorA(0,IDC_HAND)
If record=2 Then Return 1
key=GetDlgCtrlID(@CODE)
IF (@qual& 0xFFFF0000) / Int(2^16) = 513
If key > 47 & key < 97
GetWindowTextA(@CODE,thisnote,5)
note=key+keyoffset
Gosub NewNote()
EndIf
Else
GetWindowTextA(@CODE,thisnote,5)
gosub CheckMouse
EndIf
Return 1
Case @IDCONTROL
If @ControlID = 500 Then Abort=1
If @ControlID = 2 Then slide=GetState(Wnd,2)
If @ControlID = 3
If Getstate(Wnd,3)
record=1
ti=0
ListRemoveAll(mypointer,TRUE):mypointer = ListCreate()
temp = ListAdd(mypointer,NEW(note,1))
Else
record=2:Abort=0
pos = ListGetFirst(mypointer)
If #<Int>pos <> 0 Then Gosub NewNote()
record=0
EndIf
EndIf
If @ControlID=12
If buttonoffset > -1
Gosub octup
EndIf
EndIf
If @ControlID=13
If buttonoffset < 22
Gosub octdown
EndIf
EndIf
If @ControlID = 1
IF (@NOTIFYCODE = @CBNSELCHANGE):'new voice selected from combo
Def v:String
res=GetSelected(Wnd,1)
INSTRUMENT=res
v=GETSTRING(Wnd,1,GetSelected(Wnd,1))
For res = 0 To 127
If v=voice[res]
INSTRUMENT=res:res=127
EndIf
Next res
EndIf
EndIf
Case @IDHSCROLL
Select @controlid
Case 8
NOTEVOLUME=ScrollInfo(Wnd,@controlid,@CODE,@QUAL,1,1)
Def volume:Int
volume=WhatPecentageIs(NOTEVOLUME,128) :'NOTEVOLUME range 0 - 127
SetControlText wnd,10,"Volume "+Str$(volume)
Case 9
TEMPO=ScrollInfo(Wnd,@controlid,@CODE,@QUAL,1,10)
SetControlText wnd,11,"Tempo "+Str$(TEMPO)
Case 13
Def oldpos,newpos:Int
oldpos=GETSCROLLPOS(Wnd,13)
newpos=ScrollInfo(Wnd,@controlid,@CODE,@QUAL,1,1)
If oldpos > newpos
If buttonoffset < 22 Then Gosub octdown
Else
If oldpos < newpos
If buttonoffset > 0 Then Gosub octup
EndIf
EndIf
Case 15
CHANNEL=ScrollInfo(Wnd,@controlid,@CODE,@QUAL,1,2)
SetControlText wnd,14,"Channel "+Str$(CHANNEL)
EndSelect
case @IDCREATE
CenterWindow Wnd
case @IDCLOSEWINDOW
run=0
case @IDMENUPICK
select @MENUNUM
case 99:run=0
endselect
endselect
return
endsub
Sub octup
SetControlColor WhiteW[buttonoffset],White[buttonoffset],RGB(0,0,0),RGB(255,255,255)
pboffset=pboffset-12:buttonoffset=buttonoffset-7:keyoffset=keyoffset+12
If buttonoffset > -1 Then SetControlColor WhiteW[buttonoffset],White[buttonoffset],RGB(0,0,0),RGB(255,240,255)
Return
EndSub
Sub octdown
If buttonoffset > -1 Then SetControlColor WhiteW[buttonoffset],White[buttonoffset],RGB(0,0,0),RGB(255,255,255)
pboffset=pboffset+12:buttonoffset=buttonoffset+7:keyoffset=keyoffset-12
SetControlColor WhiteW[buttonoffset],White[buttonoffset],RGB(0,0,0),RGB(255,240,255)
Return
EndSub
/****************
begin a new note
*****************/
SUB NewNote
If ti <> 0 Then tie = millisecs() - ti Else tie=0
If Len(thisnote) =3
thisnote="#"+Right$(thisnote,1)
Else
thisnote=Right$(thisnote,1)
EndIf
Def playstring,OCTAVE:String
note=key+keyoffset
Select 1
Case note >= 12 & note <= 23
OCTAVE="1"
Case note >= 24 & note <= 35
OCTAVE="2"
Case note >= 36 & note <= 47
OCTAVE="3"
Case note >= 48 & note <= 59
OCTAVE="4"
Case note >= 60 & note <= 71
OCTAVE="5"
Case note >= 72 & note <= 83
OCTAVE="6"
Case note >= 84 & note <= 95
OCTAVE="7"
Case note >= 96 & note <= 107
OCTAVE="8"
Default
OCTAVE="9"
EndSelect
ti = millisecs()
Def tr:String:tr="1"
If tie <= 2000 Then tr="1"
If tie <= 1000 Then tr="2"
If tie <= 500 Then tr="4"
If tie <= 250 Then tr="8"
If tie <= 125 Then tr="16"
If tie <= 63 Then tr="32"
If tie <= 31 Then tr="64"
If tie = 0 Then tr="1"
playstring="T"+LTrim$(Str$(TEMPO))+" N"+LTrim$(Str$(CHANNEL))+" O"+OCTAVE+" I"+LTrim$(Str$(INSTRUMENT))+" V"+LTrim$(Str$(NOTEVOLUME))+" "+thisnote
If record=1:' recording
If #<Int>temp Then #<note>temp.duration = tr
temp = ListAdd(mypointer,NEW(note,1))
#<note>temp.key = note
#<note>temp.rest = " R"+tr
#<note>temp.note = "T"+LTrim$(Str$(TEMPO))+" N"+LTrim$(Str$(CHANNEL))+" O"+OCTAVE+" I"+LTrim$(Str$(INSTRUMENT))+" V"+LTrim$(Str$(NOTEVOLUME))+" "+thisnote
EndIf
If record=2:'playback
STOPMIDI$(pThread)
While pos <> 0
Def noteduration,rest:String
temp = ListGetData(pos) :' get data from linked list
note=#<note>temp.key :' set note to linked list data
thisnote=#<note>temp.note
noteduration=#<note>temp.duration
rest=#<note>temp.rest
Gosub SetKeyFocus(pboffset)
thisnote=thisnote+noteduration+rest
SetCaption Wnd,thisnote
PLAYMIDI$(thisnote)
Wait 1
If Abort = 0 Then pos = ListGetNext(pos) Else pos = 0
Wend
Else:' just playing
STOPMIDI$(pThread)
SetCaption Wnd,playstring
pThread=PLAYMIDI$(playstring,1)
EndIf
' If note < 12 | note > 108 Then SetControlColor Wnd,5,RGB(255,0,0),GetSysColor(15) else SetControlColor Wnd,5,RGB(0,0,0),GetSysColor(15)
return
endsub
Sub SetKeyFocus(offset:Int)
For t = 0 To 28
If ControlExists(WhiteW[t],note+offset)
SetFocus WhiteW[t],note+offset :' set the focus of the key we are about to play
t=28
Else
If ControlExists(BlackW[t],note+offset)
SetFocus BlackW[t],note+offset :' set the focus of the key we are about to play
t=28
EndIf
EndIf
Next t
Return
EndSub
/******************************************************
mouse is sliding over keyboard, play notes as it slides
*******************************************************/
Sub CheckMouse
If key > 47 & key < 101
If key<>oldkey & slide = 1
note=key
Gosub SetKeyFocus(0)
note=key+keyoffset
Gosub NewNote()
oldkey=key
EndIf
EndIf
return
endsub
/************
add controls
*************/
Sub AddButtonKeys
Control Wnd,@COMBOBOX,"",556,0,140,146,0x50A00603|@CTCOMBOSORT,1
CONTROL Wnd,@CHECKBOX,"Slide",4,0,70,20,0x50000003,2
CONTROL Wnd,@CHECKBOX,"Record",104,0,70,20,0x50000003,3
CONTROL Wnd,@STATIC,"",0,0,0,0,@CTEDITCENTER,5 :' this is required to set focus to when playing keys
CONTROL Wnd,@EDIT,"",1,160,782,56,0x50A01004,6
CONTROL Wnd,@SCROLLBAR,"",710,0,70,10,0x50000000,8
CONTROL Wnd,@SCROLLBAR,"",710,30,70,10,0x50000000,9
CONTROL Wnd,@STATIC,"",700,10,90,12,@CTEDITCENTER,10
CONTROL Wnd,@STATIC,"",700,40,90,12,@CTEDITCENTER,11
CONTROL Wnd,@STATIC,"",700,70,90,12,@CTEDITCENTER,12
CONTROL Wnd,@SCROLLBAR,"",710,60,70,10,0x50000000,13
CONTROL Wnd,@STATIC,"",700,100,90,12,@CTEDITCENTER,14
CONTROL Wnd,@SCROLLBAR,"",710,90,70,10,0x50000000,15
CONTROL Wnd,@BUTTON,"Abort",180,0,70,20,0x50000001,500
SETSCROLLRANGE Wnd,8,0,127
SETSCROLLPOS Wnd,8,127
SETSCROLLRANGE Wnd,9,10,320
SETSCROLLPOS Wnd,9,120
SETSCROLLRANGE Wnd,13,0,4
SETSCROLLPOS Wnd,13,3
SETSCROLLRANGE Wnd,15,0,15
SETSCROLLPOS Wnd,15,0
SetControlText wnd,10,"Volume 100"
SetControlText wnd,11,"Tempo 120"
SetControlText wnd,12,"Octave"
SetControlText wnd,14,"Channel"
return
endsub
/***********************
add menu, fill combobox
************************/
Sub FinishInit
begininsertmenu Wnd,0
MenuTitle "&File"
MenuItem "E&xit",0,99
endmenu
SetWindowColor Wnd,GetSysColor(15)
SetFont Wnd,"ms sans serif",8,400,0,1
For t = 10 To 14:SetFont Wnd,"ms sans serif",6,400,0,t:Next t
SetFont Wnd,"ms sans serif",6,400,0,11
'add voice names to combobox:
Def i:Int
for i=0 to 127
AddString Wnd,1,voice[i]
next i
SETSELECTED Wnd,1,0
return
endsub
Sub WhatPecentageIs(num1:Float,num2:Float),Float
Return Int((num1/num2)*100)
EndSub
Sub AddVoices
'List of 128 voices, in order of their MIDI index
voice = "Grand Piano","Bright Grand","Electric Grand","Honky Tonk"
voice[4] = "Rhodes","Chorus Piano","Harpsichord","Clavinet"
voice[8] = "Celesta","Glockenspiel","Music Box","Vibraphone"
voice[12] = "Marimba","Xylophone","Tubular Bells","Dulcimer"
voice[16] = "Hammond Organ","Percussion Organ","Rock Organ"
voice[19] = "Church Organ","Reed Organ","Accordion","Harmonica"
voice[23] = "Tango Accordion","Accoustic Nylon Guitar"
voice[25] = "Accoustic Steel Guitar","Electric Jazz Guitar"
voice[27] = "Electric Clean Guitar","Electric Mute Guitar"
voice[29] = "Overdrive Guitar","Distorted Guitar","Guitar Harmonic"
voice[32] = "Accoustic Bass","Electric Bass Finger","Electric Bass Pick"
voice[35] = "Fretless Bass","Slap Bass One","Slap Bass Two"
voice[38] = "Synth Bass One","Synth Bass Two","Violin","Viola","Cello"
voice[43] = "Contrabass","Tremolo Strings","Pizzicato Strings"
voice[46] = "Orchestra Harp","Timpani","String Ensemble One"
voice[49] = "String Ensemble Two","Synth Strings One","Synth Strings Two"
voice[52] = "Choir Ahhs","Voice Oohs","Synth Voice","Orchestra Hit"
voice[56] = "Trumpet","Trombone","Tuba","Mute Trumpet","French Horn"
voice[61] = "Brass Section","Synth Brass One","Synth Brass Two"
voice[64] = "Soprano Sax","Alto Sax","Tenor Sax","Bari Sax","Oboe"
voice[69] = "English Horn","Bassoon","Clarinet","Piccolo","Flute"
voice[74] = "Recorder","Pan Flute","Bottle Blow","Shakuhachi","Whistle"
voice[79] = "Ocarina","Square Wave","Sawtooth","Caliope","Chiff Lead"
voice[84] = "Charang","Solo Synth VX","Brite Saw","Brass and Lead"
voice[88] = "Fantasia Pad","Warm Pad","Poly Synth Pad","Space Vox Pad"
voice[92] = "Bowd Glas Pad","Metal Pad","Halo Pad","Sweep Pad"
voice[96] = "Ice Rain","Sound Track","Crystal","Atmosphere","Brightness"
voice[101] = "Goblin","Echo Drops","Star Theme","Sitar","Banjo","Shamisen"
voice[107] = "Koto","Kalimba","Bagpipe","Fiddle","Shanai"
voice[112] = "Tinkle Bell","Agogo","Steel Drums","Wood Block","Taiko Drum"
voice[117] = "Melodic Tom","Synth Drum","Rev Cymbal"
voice[120] = "Guitar Fret Noise","Breath Noise","Sea Shore","Bird Tweet"
voice[124] = "Phone Ring","Helicopter","Applause","Gunshot"
return
endsub
Sub ScrollInfo(win:Window,cid:Int,code:Int,qual:Int,lineup:Int,pageup:Int),Int
SELECT code
Case @SBTHUMBPOS
Case& @SBTHUMBTRACK
SETSCROLLPOS win,cid,qual
Case @SBLINEUP
SETSCROLLPOS win,cid,(GETSCROLLPOS(win,cid)-lineup)
Case @SBLINEDOWN
SETSCROLLPOS win,cid,(GETSCROLLPOS(win,cid)+lineup)
Case @SBPAGEUP
SETSCROLLPOS win,cid,(GETSCROLLPOS(win,cid)-pageup)
Case @SBPAGEDOWN
SETSCROLLPOS win,cid,(GETSCROLLPOS(win,cid)+pageup)
EndSelect
Return GETSCROLLPOS(win,cid)
EndSub
Did you manage to get what you were after ?
Or do you still need more help ?