Wie bekommt man das (am besten) asynchron hin?
Verfasst: 28.12.2020 15:51
Hallo Leute,
hier war das Thema Midi gerade so präsent, daher hier einmal eine allgemeine Thread/Async-Frage (mit Bezug auf Musik).
Wie könnte man so etwas (am besten) asynchron hinbekommen.
(Also ohne das Delay)
hier war das Thema Midi gerade so präsent, daher hier einmal eine allgemeine Thread/Async-Frage (mit Bezug auf Musik).
Wie könnte man so etwas (am besten) asynchron hinbekommen.
(Also ohne das Delay)
Code: Alles auswählen
;Einrücken: Strg + I
;Nur ein kleiner Testcode
EnableExplicit
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Global.i hMidiOut
Procedure MidiOutMessage(hMidi,iStatus,iChannel,iData1,iData2)
Protected.i dwMessage
dwMessage = iStatus | iChannel | (iData1 << 8 ) | (iData2 << 16)
ProcedureReturn midiOutShortMsg_(hMidi, dwMessage)
EndProcedure
Procedure SetInstrumentPerChannel(channel, instrument)
MidiOutMessage(hMidiOut, $C0, channel, instrument, 0)
EndProcedure
Procedure StopNote(channel, note)
MidiOutMessage(hMidiOut, $90, channel, Note, 0)
EndProcedure
Procedure PlayNote(channel, note, volume)
MidiOutMessage(hMidiOut, $90, channel, note , volume)
EndProcedure
Define midi.MIDIOUTCAPS, devices, devnum, midiport
devices = midiOutGetNumDevs_()
For devnum = - 1 To devices - 1
If midiOutGetDevCaps_(devnum,@midi,SizeOf(MIDIOUTCAPS))=0
If midi\wVoices > 0
midiport=devnum
EndIf
EndIf
Next
Define *hMidiOut
If midiOutOpen_(@hMidiOut,midiport,0,0,0) <> #MMSYSERR_NOERROR
MessageRequester("Fehler", "Keine Midi-Ausgabe möglich.", #PB_MessageRequester_Error)
End
EndIf
Procedure Decode_MidiString(channel.i, MidiStr.s, bpm.i = 120, volume.i = 50)
Protected.i index = 1
Protected.s nstr, ns, ds, ts
Protected.i note, octave, dots, i
Protected.f duration, bps, beat, mbeats
If channel = 0
ProcedureReturn -1
Debug "Kanal muss größer 0 sein."
EndIf
bps.f = bpm / 60
beat.f = (1 / bps) * 1000
Repeat
nstr = StringField(MidiStr, index, "/")
If nstr <> #Null$
ns = StringField(nstr, 1, ":")
octave = Val(StringField(nstr, 2, ":"))
ds = StringField(nstr, 3, ":")
ts = Right(nstr, 1) ;Um den Takt zu ermitteln.
Select UCase(ns)
Case "C"
note = 0
Case "#C", "bD"
note = 1
Case "D"
note = 2
Case "#D", "bE"
note = 3
Case "E"
note = 4
Case "F"
note = 5
Case "#F", "bG"
note = 6
Case "G"
note = 7
Case "#G", "bA"
note = 8
Case "A"
note = 9
Case "#A", "bB", "bH"
note = 10
Case "B", "H"
note = 11
Case "R" ;Pause
note = 255
Default
MessageRequester("Fehler", ~"Eine ungültige Note eingegeben.\nDie Eingabe: \""+ns+~"\" ist ungültig.", #PB_MessageRequester_Error)
ProcedureReturn -1
EndSelect
note = (octave * 12) + note
Select UCase(Left(ds, 1))
Case "Q"
duration = 1 ;Viertel-Note
Case "H"
duration = 2 ;Halbe-Note
Case "W"
duration = 4 ;Ganze-Note
Case "E"
duration = 0.5 ;Achtel-Note
Case "S"
duration = 0.25 ;Sechzehntel-Note
Case "T"
duration = 0.125 ;Zweiunddreißigstel-Note
Case "F"
duration = 0.0625 ;Vierundsechzigstel-Note
Default
MessageRequester("Fehler", ~"Eine ungültige Notenlänge angegeben.\nDie Eingabe: \""+ds+~"\" ist ungültig.", #PB_MessageRequester_Error)
ProcedureReturn -1
EndSelect
dots = CountString(UCase(ds), "D")
If duration > 0 And Len(ds) > 1 And dots > 0 And (dots = Len(ds)-1)
For i=1 To dots
duration * 1.5
Next
ElseIf duration > 0 And Len(ds) > 1 And (dots <> Len(ds)-1)
MessageRequester("Fehler", ~"Eine ungültige Punktierung angegeben.\nDie Eingabe: \""+UCase(ds)+~"\" ist ungültig.", #PB_MessageRequester_Error)
ProcedureReturn -1
EndIf
mbeats = mbeats + duration
If note < 255
PlayNote(channel, note, volume)
Delay(beat * duration)
StopNote(channel, note)
EndIf
If ts = "|"
Debug "Count: " + StrF(mbeats)
mbeats = 0
EndIf
EndIf
index + 1
Until nstr = ""
EndProcedure
;-GUI
Global evt
If OpenWindow(0, 0, 0, 100, 100, "Midi-Test", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
StartDrawing(WindowOutput(0))
DrawText(10, 10, "Bitte warten!")
StopDrawing()
;...
SetInstrumentPerChannel(1, 10)
;SetInstrumentPerChannel(2, 1)
Decode_MidiString(1, "g:6:q/a:6:q/b:6:q/c:7:q/d:7:q/e:7:q/#f:7:q:|/g:7:q", 120, 100)
;...
Repeat
evt = WaitWindowEvent()
;....
Until evt = #PB_Event_CloseWindow
EndIf
midiOutClose_(@hMidiOut)
CompilerElse
MessageRequester("Fehler", ~"Dieser Code läuft nur unter Windows.\nDanke für Ihr Verständnis.", #PB_MessageRequester_Error)
CompilerEndIf