Interface zur Ansprechung der MIDI-Schnittstelle

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Interface zur Ansprechung der MIDI-Schnittstelle

Beitrag von NicTheQuick »

Hi Leute!

Ich habe heute mal eben ein kleines Interface gebastelt, mit dem man
ganz einfach die MIDI-Funktionen aus der API benutzen kann.

Ein kleines Tastatur-Keyboard ist dabei. Halbtonleiter ist A, W, S, E, D, F,
T, G, Z, H, U, J, K. Bild hoch und runter für Lautstärke. ESC zum
Beenden. Cursor links und rechts zur Instrumentenauswahl. Cursor hoch
und runter zur Auswahl der Note auf Taste A. Leertaste zum Wechseln
zwischen Kanal 1 und 10 (Schlagzeug).

///Edit:
Hier noch als EXE-Datei für Nicht-PB-ler: Interface-Test.exe

Beim nächsten Update wird auch noch ein Callback für den MIDI-Input
dabei sein. Freut euch! :mrgreen:

Code: Alles auswählen

Interface PB_MIDI
  GetLastErrorText.s()
  GetLastErrorNr.l()
  
  Kill.l()
  
  OpenOutputDevice.l(DeviceID.l)
  CloseOutputDevice.l()
  OpenInputDevice.l(DeviceID.l)
  CloseInputDevice.l()
  StartInput.l()
  StopInput.l()
  ResetInput.l()
  
  ProgramChange.l(Channel.b, Voice.b)
  NoteOn.l(Channel.b, Note.b, Velocity.b)
  NoteOff.l(Channel.b, Note.b, Velocity.b)
  NoteOffAlternate.l(Channel.b, Note.b)
  AllNotesOff.l(Channel.b)
  ChangeController.l(Channel.b, Controller.b, Value.b)
  ChannelPressure.l(Channel.b, Value.b)
  KeyAftertouch.l(Channe.b, Note.b, Value.b)
  PitchWheel.l(Channel.b, Value.w)
EndInterface
Structure PB_MIDI_Struc
  VTable.l
  
  ;Functions
  fGetLastErrorText.l
  fGetLastErrorNr.l
  fKill.l
  fOpenOutputDevice.l
  fCloseOutputDevice.l
  fOpenInputDevice.l
  fCloseInputDevice.l
  fStartInput.l
  fStopInput.l
  fResetInput.l
  fProgramChange.l
  fNoteOn.l
  fNoteOff.l
  fNoteOffAlternate.l
  fAllNotesOff.l
  fChangeController.l
  fChannelPressure.l
  fKeyAftertouch.l
  fPitchWheel.l
  
  ;Data
  OutDevice.l
  InDevice.l
  InCallback.l
  hOutDevice.l
  hInDevice.l
  LastError.l
  LastErrorFunc.l
EndStructure
Structure PB_MIDI_Msg
  Channel.b
  Note.b
  Velocity.b
  Null.b
EndStructure 

#MIDIERR_BADOPENMODE = #MIDIERR_BASE + 6

Procedure.s PB_MIDI_GetLastErrorText(*PM.PB_MIDI_Struc)
  Protected ErrorText.s
  ErrorText = "Error: "
  Select *PM\LastError
    Case #MMSYSERR_NOERROR : ErrorText + "No Error"
    Case #MIDIERR_NODEVICE : ErrorText + "No MIDI port was found. This error occurs only when the mapper is opened."
    Case #MMSYSERR_ALLOCATED : ErrorText + "The specified resource is already allocated."
    Case #MMSYSERR_BADDEVICEID : ErrorText + "The specified device identifier is out of range."
    Case #MMSYSERR_INVALPARAM : ErrorText + "The specified pointer or structure is invalid."
    Case #MMSYSERR_NOMEM : ErrorText + "The system is unable to allocate or lock memory."
    Case #MMSYSERR_INVALHANDLE : ErrorText + "The specified device handle is invalid."
    Case #MIDIERR_BADOPENMODE : ErrorText + "The application sent a message without a status byte to a stream handle."
    Case #MIDIERR_NOTREADY : ErrorText + "The hardware is busy with other data."
    Case #MIDIERR_STILLPLAYING : ErrorText + "Buffers are still in the queue."
    
    Default : ErrorText + "Code " + Str(*PM\LastError)
  EndSelect
  ErrorText + #CRLF$ + "Function: "
  Select *PM\LastErrorFunc
    Case  0 : ErrorText + "No Function"
    Case  1 : ErrorText + "OpenOutptDevice"
    Case  2 : ErrorText + "OpenInputDevice"
    Case  3 : ErrorText + "StartInput"
    Case  4 : ErrorText + "StopInput"
    Case  5 : ErrorText + "ResetInput"
    Case  6 : ErrorText + "ProgramChange"
    Case  7 : ErrorText + "NoteOn"
    Case  8 : ErrorText + "NoteOff"
    Case  9 : ErrorText + "NoteOffAlternate"
    Case 10 : ErrorText + "AllNotesOff"
    Case 11 : ErrorText + "ChangeController"
    Case 12 : ErrorText + "ChannelPressure"
    Case 13 : ErrorText + "KeyAftertouch"
    Case 14 : ErrorText + "PitchWheel"
    Case 15 : ErrorText + "CloseOutputDevice"
    Case 16 : ErrorText + "CloseInputDevice"
    Default : ErrorText + "Unknown"
  EndSelect
  *PM\LastError = #MMSYSERR_NOERROR
  *PM\LastErrorFunc = 0
  ProcedureReturn ErrorText
EndProcedure
Procedure PB_MIDI_GetLastErrorNr(*PM.PB_MIDI_Struc)
  Protected Error.l
  Error = *PM\LastError
  *PM\LastError = 0
  ProcedureReturn Error
EndProcedure

Procedure PB_MIDI_OpenOutputDevice(*PM.PB_MIDI_Struc, DeviceID.l)
  Protected Error.l
  Error = midiOutOpen_(@*PM\hOutDevice, DeviceID, 0, 0, 0)
  If Error = #MMSYSERR_NOERROR
    *PM\OutDevice = DeviceID
    ProcedureReturn #True
  Else
    *PM\LastErrorFunc = 1
    *PM\LastError = Error
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_CloseOutputDevice(*PM.PB_MIDI_Struc)
  Protected Error.l
  Error = midiOutClose_(*PM\hOutDevice)
  If Error = #MMSYSERR_NOERROR
    *PM\OutDevice = 0
    *PM\hOutDevice = 0
    ProcedureReturn #True
  Else
    *PM\LastErrorFunc = 15
    *PM\LastError = Error
    ProcedureReturn #False
  EndIf
EndProcedure

Procedure PB_MIDI_InCallback(hMidiIn.l, wMsg.l, *PM.PB_MIDI_Struc, dwMideMessage.l, dwTimeStamp.l)

EndProcedure
Procedure PB_MIDI_OpenInputDevice(*PM.PB_MIDI_Struc, DeviceID.l, Callback.l)
  Protected Error.l
  
  Error = midiInOpen_(@*PM\hInDevice, DeviceID, @PB_MIDI_InCallback(), *PM, #CALLBACK_FUNCTION)
  If Error = #MMSYSERR_NOERROR
    *PM\InDevice = DeviceID
    *PM\InCallback = Callback
    ProcedureReturn #True
  Else
    *PM\LastErrorFunc = 2
    *PM\LastError = Error
    ProcedureReturn #False
  EndIf 
EndProcedure
Procedure PB_MIDI_CloseInputDevice(*PM.PB_MIDI_Struc)
  Protected Error.l
  Error = midiInClose_(*PM\hInDevice)
  If Error = #MMSYSERR_NOERROR
    *PM\InDevice = 0
    *PM\hInDevice = 0
    *PM\InCallback = 0
    ProcedureReturn #True
  Else
    *PM\LastErrorFunc = 16
    *PM\LastError = Error
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_StartInput(*PM.PB_MIDI_Struc)
  Protected Error.l
  
  Error = midiInStart_(*PM\hInDevice)
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastErrorFunc = 3
    *PM\LastError = Error
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_StopInput(*PM.PB_MIDI_Struc)
  Protected Error.l
  
  Error = midiInStop_(*PM\hInDevice)
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastErrorFunc = 4
    *PM\LastError = Error
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_ResetInput(*PM.PB_MIDI_Struc)
  Protected Error.l
  
  Error = midiInReset_(*PM\hInDevice)
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastErrorFunc = 5
    *PM\LastError = Error
    ProcedureReturn #False
  EndIf
EndProcedure

;Channel: 0-15
;Voice: 0-127
;Note: 0-127
;Controller: 0-127
;Value: 0-127
;Value von PitchWheel: 0-32768 (?)
Procedure PB_MIDI_ProgramChange(*PM.PB_MIDI_Struc, Channel.b, Voice.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $C0 + Channel
  Msg\Note = Voice
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekW(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 6
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_NoteOn(*PM.PB_MIDI_Struc, Channel.b, Note.b, Velocity.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $90 + Channel
  Msg\Note = Note
  Msg\Velocity = Velocity
  Msg\Null = 0
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 7
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_NoteOff(*PM.PB_MIDI_Struc, Channel.b, Note.b, Velocity.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $80 + Channel
  Msg\Note = Note
  Msg\Velocity = Velocity
  Msg\Null = 0
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 8
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_NoteOffAlternate(*PM.PB_MIDI_Struc, Channel.b, Note.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $90 + Channel
  Msg\Note = Note
  Msg\Velocity = 0
  Msg\Null = 0
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 9
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_AllNotesOff(*PM.PB_MIDI_Struc, Channel.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $B0 + Channel
  Msg\Note = $7B
  Msg\Velocity = 0
  Msg\Null = 0
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 10
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_ChangeController(*PM.PB_MIDI_Struc, Channel.b, Controller.b, Value.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $B0 + Channel
  Msg\Note = Controller
  Msg\Velocity = Value
  Msg\Null = 0
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 11
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_ChannelPressure(*PM.PB_MIDI_Struc, Channel.b, Value.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $D0 + Channel
  Msg\Note = Value
  Msg\Velocity = 0
  Msg\Null = 0
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 12
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_KeyAftertouch(*PM.PB_MIDI_Struc, Channel.b, Note.b, Value.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $A0 + Channel
  Msg\Note = Note
  Msg\Velocity = Value
  Msg\Null = 0
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 12
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_PitchWheel(*PM.PB_MIDI_Struc, Channel.b, Value.w)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $E0 + Channel
  Msg\Null = 0
  PokeW(@Msg, Value)
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 12
    ProcedureReturn #False
  EndIf
EndProcedure

Procedure PB_MIDI_Kill(*PM.PB_MIDI_Struc)
  While midiInClose_(*PM\hInDevice) = #MIDIERR_STILLPLAYING : Wend 
  While midiOutClose_(*PM\hOutDevice) = #MIDIERR_STILLPLAYING : Wend 
  FreeMemory(*PM)
  ProcedureReturn #True
EndProcedure

Procedure PB_MIDI_Create()
  Protected *PM.PB_MIDI_Struc
  
  *PM = AllocateMemory(SizeOf(PB_MIDI_Struc))
  If *PM = 0 : ProcedureReturn #False : EndIf
  *PM\VTable = *PM + 4
  *PM\fGetLastErrorText  = @PB_MIDI_GetLastErrorText()
  *PM\fGetLastErrorNr    = @PB_MIDI_GetLastErrorNr()
  *PM\fKill              = @PB_MIDI_Kill()
  *PM\fOpenOutputDevice  = @PB_MIDI_OpenOutputDevice()
  *PM\fOpenInputDevice   = @PB_MIDI_OpenInputDevice()
  *PM\fStartInput        = @PB_MIDI_StartInput()
  *PM\fStopInput         = @PB_MIDI_StopInput()
  *PM\fResetInput        = @PB_MIDI_ResetInput()
  *PM\fProgramChange     = @PB_MIDI_ProgramChange()
  *PM\fNoteOn            = @PB_MIDI_NoteOn()
  *PM\fNoteOff           = @PB_MIDI_NoteOff()
  *PM\fNoteOffAlternate  = @PB_MIDI_NoteOffAlternate()
  *PM\fAllNotesOff       = @PB_MIDI_AllNotesOff()
  *PM\fChangeController  = @PB_MIDI_ChangeController()
  *PM\fChannelPressure   = @PB_MIDI_ChannelPressure()
  *PM\fKeyAftertouch     = @PB_MIDI_KeyAftertouch()
  *PM\fPitchWheel        = @PB_MIDI_PitchWheel()
  
  ProcedureReturn *PM
EndProcedure

Procedure MIDIRequester(*OutDevice.l, *InDevice.l) 
  Protected WinID.l
  Protected List1.l, List2.l, But1.l, But2.l, Txt1.l, Txt2.l, Txt3.l, Txt4.l
  Protected MaxOutDev.l, InfoOut.MIDIOUTCAPS, InDev.l, OutDev.l, Quit.l, Ok.l, EventID.l, a.l
  Protected Width.l, Column.l, Offset.l
  
  #MOD_WAVETABLE = 6 
  #MOD_SWSYNTH = 7 
  #MIDIRequ_InSet = 2 
  #MIDIRequ_OutSet = 1 

  Width = 400 
  WinID = OpenWindow(#PB_Any, 0, 0, Width, 270, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "MIDI-Requester") 
  If WinID
    If CreateGadgetList(WindowID(WinID)) 
      Column = (Width - 20) / 2 
      Offset = (Width / 2) + 5 
      
      TextGadget(#PB_Any, 5, 5, Column, 18, "Output-Device:", #PB_Text_Center | #PB_Text_Border) 
      List1 = ListViewGadget(#PB_Any, 5, 23, Column, 100) 
        MaxOutDev = midiOutGetNumDevs_() 
        If MaxOutDev 
          For a = -1 To MaxOutDev - 1 
            midiOutGetDevCaps_(a, InfoOut, SizeOf(MIDIOUTCAPS)) 
            AddGadgetItem(List1, -1, PeekS(@InfoOut\szPname[0], 32)) 
          Next 
        Else 
          AddGadgetItem(List1, -1, "(no output device)") 
          DisableGadget(List1, 1) 
        EndIf 
      If *OutDevice = 0 : DisableGadget(List1, 1) : EndIf
      
      TextGadget(#PB_Any, Offset, 5, Column, 18, "Input-Device:", #PB_Text_Center | #PB_Text_Border) 
      List2 = ListViewGadget(#PB_Any, Offset, 23, Column, 100) 
        MaxInDev.l = midiInGetNumDevs_() 
        InfoIn.MIDIINCAPS 
        If MaxInDev 
          For a = 0 To MaxInDev - 1 
            midiInGetDevCaps_(a, InfoIn, SizeOf(MIDIINCAPS)) 
            AddGadgetItem(List2, -1, PeekS(@InfoIn\szPname[0], 32)) 
          Next 
        Else 
          AddGadgetItem(List2, -1, "(no input device)") 
          DisableGadget(List2, 1) 
        EndIf 
      If *InDevice = 0 : DisableGadget(List2, 1) : EndIf
      
      But1 = ButtonGadget(#PB_Any, 5, 240, Column, 24, "&OK") 
      But2 = ButtonGadget(#PB_Any, Offset, 240, Column, 24, "&Cancel") 
      
      Frame3DGadget(#PB_Any, 5, 130, Width - 10, 100, "Info of Output-Device", 0) 
       Txt1 = TextGadget(#PB_Any, 10, 145, Width - 20, 18, "Version:") 
       Txt2 = TextGadget(#PB_Any, 10, 165, Width - 20, 18, "Technology:") 
       Txt3 = TextGadget(#PB_Any, 10, 185, Width - 20, 18, "Max. Voices:") 
       Txt4 = TextGadget(#PB_Any, 10, 205, Width - 20, 18, "Polyphonie:") 
      
      OutDev = 0 
      InDev = 0 
      Quit = #False 
      Ok = #False 
      Repeat 
        If GetGadgetState(List1) > -1 Or GetGadgetState(List2) > -1 
          DisableGadget(But1, 0) 
        Else 
          DisableGadget(But1, 1) 
        EndIf 
        
        If InDev <> GetGadgetState(List2) 
          InDev = GetGadgetState(List2) 
        EndIf 
        
        If GetGadgetState(List1) <> OutDev 
          OutDev = GetGadgetState(List1) 
          midiOutGetDevCaps_(OutDev - 1, InfoOut, SizeOf(MIDIOUTCAPS)) 
          SetGadgetText(Txt1, "Version: " + Str(InfoOut\vDriverVersion >> 8) + "." + Str(InfoOut\vDriverVersion & FF)) 
          Select InfoOut\wTechnology 
            Case #MOD_MIDIPORT :  TmpS.s = "Hardware Port" 
            Case #MOD_SYNTH :     TmpS.s = "Synthesizer" 
            Case #MOD_SQSYNTH :   TmpS.s = "Square Wave Synthesizer" 
            Case #MOD_FMSYNTH :   TmpS.s = "FM Synthesizer" 
            Case #MOD_MAPPER :    TmpS.s = "Microsoft MIDI Mapper" 
            Case #MOD_WAVETABLE : TmpS.s = "Hardware Wavetable Synthesizer" 
            Case #MOD_SWSYNTH :   TmpS.s = "Software Synthesizer" 
            Default: TmpS.s = "(Error Code " + Str(InfoOut\wTechnology) + ")" 
          EndSelect 
          SetGadgetText(Txt2, "Technology: " + TmpS) 
          If InfoOut\wVoices = 0 : TmpS.s = "inf" : Else : TmpS.s = Str(InfoOut\wVoices) : EndIf 
          SetGadgetText(Txt3, "Max. Voices: " + TmpS) 
          If InfoOut\wNotes = 0 : TmpS.s = "inf" : Else : TmpS.s = Str(InfoOut\wNotes) : EndIf 
          SetGadgetText(Txt4, "Polyphonie: " + TmpS) 
        EndIf 
        
        EventID = WaitWindowEvent() 
        Select EventID 
          Case #PB_EventCloseWindow 
            Quit = #True 
            Ok = #False 
          Case #PB_EventGadget 
            Select EventGadgetID() 
              Case But1 
                If *OutDevice : PokeL(*OutDevice, OutDev - 1) : EndIf
                If *InDevice : PokeL(*InDevice, InDev)  : EndIf
                Quit = #True 
                Ok = 3 
                If (OutDev = -1 Or CountGadgetItems(List1) = 0) And Ok & #MIDIRequ_OutSet : Ok ! #MIDIRequ_OutSet : EndIf 
                If (InDev = -1 Or CountGadgetItems(List2) = 0) And Ok & #MIDIRequ_InSet : Ok ! #MIDIRequ_InSet : EndIf 
              Case But2
                Quit = #True 
                Ok = #False 
            EndSelect 
        EndSelect 
      Until Quit 
      CloseWindow(WinID) 
      ProcedureReturn Ok 
    EndIf 
  EndIf 
  ProcedureReturn #False
EndProcedure 

OutDevice.l 
MIDIResult.l = MIDIRequester(@OutDevice, 0)

If MIDIResult & #MIDIRequ_OutSet = 0 : End : EndIf
*midi.PB_MIDI = PB_MIDI_Create()
*midi\OpenOutputDevice(OutDevice)

Voice.l = 0
Channel.l = 0
Vol.l = 127
NoteOffset.l = 36
Dim Note.l(127)

Win_Key.l = OpenWindow(#PB_Any, 0, 0, 100, 90, #PB_Window_BorderLess | #PB_Window_ScreenCentered, "Keyboard")
If Win_Key
  If CreateGadgetList(WindowID(Win_Key))
    Txt1.l = TextGadget(#PB_Any, 0,  0, 100, 18, "Beenden mit ESC", #PB_Text_Center)
    Txt2.l = TextGadget(#PB_Any, 0, 18, 100, 18, "Instrument: " + Str(Voice + 1), #PB_Text_Center)
    Txt3.l = TextGadget(#PB_Any, 0, 36, 100, 18, "Ton: " + Str(NoteOffset), #PB_Text_Center)
    Txt4.l = TextGadget(#PB_Any, 0, 54, 100, 18, "Kanal: " + Str(Channel + 1), #PB_Text_Center)
    Txt5.l = TextGadget(#PB_Any, 0, 72, 100, 18, "Lautstärke: " + Str(Vol), #PB_Text_Center)
  EndIf
  
  Repeat
    Select WaitWindowEvent()
      Case #WM_KEYDOWN
        Select EventwParam()
          Case #VK_ESCAPE : Break
          
          Case #VK_SPACE
            If Channel = 0 : Channel = 9 : Else : Channel = 0 : EndIf
            SetGadgetText(Txt4, "Kanal: " + Str(Channel + 1))
          
          Case #VK_PRIOR
            If Vol < 127 : Vol + 1 : EndIf
            SetGadgetText(Txt5, "Lautstärke: " + Str(Vol))
          
          Case #VK_NEXT
            If Vol > 0 : Vol - 1 : EndIf
            SetGadgetText(Txt5, "Lautstärke: " + Str(Vol))
          
          Case #VK_RIGHT
            If Voice < 127 : Voice + 1 : EndIf
            *midi\ProgramChange(0, Voice)
            SetGadgetText(Txt2, "Instrument: " + Str(Voice + 1))
          Case #VK_LEFT
            If Voice > 0 : Voice - 1 : EndIf
            *midi\ProgramChange(0, Voice)
            SetGadgetText(Txt2, "Instrument: " + Str(Voice + 1))
          
          Case #VK_UP
            If NoteOffset < 115 : NoteOffset + 1 : EndIf
            SetGadgetText(Txt3, "Ton: " + Str(NoteOffset))
          Case #VK_DOWN
            If NoteOffset > 0 : NoteOffset - 1 : EndIf
            SetGadgetText(Txt3, "Ton: " + Str(NoteOffset))
          
          Case #VK_A : If Note(NoteOffset +  0) = 0 : *midi\NoteOn(Channel, NoteOffset +  0, Vol) : Note(NoteOffset +  0) = 1 : EndIf
          Case #VK_W : If Note(NoteOffset +  1) = 0 : *midi\NoteOn(Channel, NoteOffset +  1, Vol) : Note(NoteOffset +  1) = 1 : EndIf
          Case #VK_S : If Note(NoteOffset +  2) = 0 : *midi\NoteOn(Channel, NoteOffset +  2, Vol) : Note(NoteOffset +  2) = 1 : EndIf
          Case #VK_E : If Note(NoteOffset +  3) = 0 : *midi\NoteOn(Channel, NoteOffset +  3, Vol) : Note(NoteOffset +  3) = 1 : EndIf
          Case #VK_D : If Note(NoteOffset +  4) = 0 : *midi\NoteOn(Channel, NoteOffset +  4, Vol) : Note(NoteOffset +  4) = 1 : EndIf
          Case #VK_F : If Note(NoteOffset +  5) = 0 : *midi\NoteOn(Channel, NoteOffset +  5, Vol) : Note(NoteOffset +  5) = 1 : EndIf
          Case #VK_T : If Note(NoteOffset +  6) = 0 : *midi\NoteOn(Channel, NoteOffset +  6, Vol) : Note(NoteOffset +  6) = 1 : EndIf
          Case #VK_G : If Note(NoteOffset +  7) = 0 : *midi\NoteOn(Channel, NoteOffset +  7, Vol) : Note(NoteOffset +  7) = 1 : EndIf
          Case #VK_Z : If Note(NoteOffset +  8) = 0 : *midi\NoteOn(Channel, NoteOffset +  8, Vol) : Note(NoteOffset +  8) = 1 : EndIf
          Case #VK_H : If Note(NoteOffset +  9) = 0 : *midi\NoteOn(Channel, NoteOffset +  9, Vol) : Note(NoteOffset +  9) = 1 : EndIf
          Case #VK_U : If Note(NoteOffset + 10) = 0 : *midi\NoteOn(Channel, NoteOffset + 10, Vol) : Note(NoteOffset + 10) = 1 : EndIf
          Case #VK_J : If Note(NoteOffset + 11) = 0 : *midi\NoteOn(Channel, NoteOffset + 11, Vol) : Note(NoteOffset + 11) = 1 : EndIf
          Case #VK_K : If Note(NoteOffset + 12) = 0 : *midi\NoteOn(Channel, NoteOffset + 12, Vol) : Note(NoteOffset + 12) = 1 : EndIf
        EndSelect
      
      Case #WM_KEYUP
        Select EventwParam()
          Case #VK_A : If Note(NoteOffset +  0) : *midi\NoteOff(Channel, NoteOffset +  0, 0) : Note(NoteOffset +  0) = 0 : EndIf
          Case #VK_W : If Note(NoteOffset +  1) : *midi\NoteOff(Channel, NoteOffset +  1, 0) : Note(NoteOffset +  1) = 0 : EndIf
          Case #VK_S : If Note(NoteOffset +  2) : *midi\NoteOff(Channel, NoteOffset +  2, 0) : Note(NoteOffset +  2) = 0 : EndIf
          Case #VK_E : If Note(NoteOffset +  3) : *midi\NoteOff(Channel, NoteOffset +  3, 0) : Note(NoteOffset +  3) = 0 : EndIf
          Case #VK_D : If Note(NoteOffset +  4) : *midi\NoteOff(Channel, NoteOffset +  4, 0) : Note(NoteOffset +  4) = 0 : EndIf
          Case #VK_F : If Note(NoteOffset +  5) : *midi\NoteOff(Channel, NoteOffset +  5, 0) : Note(NoteOffset +  5) = 0 : EndIf
          Case #VK_T : If Note(NoteOffset +  6) : *midi\NoteOff(Channel, NoteOffset +  6, 0) : Note(NoteOffset +  6) = 0 : EndIf
          Case #VK_G : If Note(NoteOffset +  7) : *midi\NoteOff(Channel, NoteOffset +  7, 0) : Note(NoteOffset +  7) = 0 : EndIf
          Case #VK_Z : If Note(NoteOffset +  8) : *midi\NoteOff(Channel, NoteOffset +  8, 0) : Note(NoteOffset +  8) = 0 : EndIf
          Case #VK_H : If Note(NoteOffset +  9) : *midi\NoteOff(Channel, NoteOffset +  9, 0) : Note(NoteOffset +  9) = 0 : EndIf
          Case #VK_U : If Note(NoteOffset + 10) : *midi\NoteOff(Channel, NoteOffset + 10, 0) : Note(NoteOffset + 10) = 0 : EndIf
          Case #VK_J : If Note(NoteOffset + 11) : *midi\NoteOff(Channel, NoteOffset + 11, 0) : Note(NoteOffset + 11) = 0 : EndIf
          Case #VK_K : If Note(NoteOffset + 12) : *midi\NoteOff(Channel, NoteOffset + 12, 0) : Note(NoteOffset + 12) = 0 : EndIf
        EndSelect
    EndSelect
  ForEver
EndIf

*midi\Kill()
Zuletzt geändert von NicTheQuick am 10.01.2007 16:46, insgesamt 3-mal geändert.
Nik
Beiträge: 132
Registriert: 04.02.2005 19:57

Beitrag von Nik »

WOW :allright: :shock:
www.KoMaNi.de
Eine kleine Gruppe von Hobby Programmierern, die gerade einen Instant Messenger natürlich in PureBasic schreiben.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Gefällt mir, kann leider nicht Spielen, völlig unbegabt :(
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Batze
Beiträge: 1492
Registriert: 03.06.2005 21:58
Wohnort: Berlin
Kontaktdaten:

Beitrag von Batze »

irgendwie geht das bei mir nicht. :?
Hier sind meine Codes (aber die Seite geht gerade nicht):
http://www.basicpure.de.vu
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

@Batze: Was genau funktioniert bei dir denn nicht?
Benutzeravatar
MVXA
Beiträge: 3823
Registriert: 11.09.2004 00:45
Wohnort: Bremen, Deutschland
Kontaktdaten:

Beitrag von MVXA »

Finde ich genial :allright:. Könntest du vielleicht noch eine Option einbauen,
dass man sich z.b. auch ne Orgel auswählen kann ^^? Danke!
Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

@MVXA:
Kann man doch. Einfach mit der rechten Cursortaste eine MIDI-Nummer
zwischen 17 und 24 auswählen. Da sind die Orgeln.
Benutzeravatar
MVXA
Beiträge: 3823
Registriert: 11.09.2004 00:45
Wohnort: Bremen, Deutschland
Kontaktdaten:

Beitrag von MVXA »

Ich dachte damit kann man nur "Ton" einstellen. Hätte mir den Source
genauer ansehen sollen >__<.
Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Das Interface wächst und gedeiht. Ich bin gerade dabei noch die
allgemeinen XG-Funktionen einzubauen für YAMAHA-Synthesizer.

Der Callback für den MIDI-Eingang und die SysEx-Messages funktionieren
jetzt auch. Ein Beispiel-Callback ist die Procedure [c]InCallback()[/c].

Leider hatte ich gerade keine Zeit noch für alles ein Beispiel einzubauen, aber wer etwas nicht versteht, kann ja nachfragen. :wink:

Hier ist der Code: (962 Zeilen)

Code: Alles auswählen

Interface PB_MIDI
  GetLastErrorText.s()
  GetLastErrorNr.l()
  
  Kill.l()
  
  ;{- MIDI-Functions
  OpenOutputDevice.l(DeviceID.l)
  CloseOutputDevice.l()
  OpenInputDevice.l(DeviceID.l, Callback.l)
  CloseInputDevice.l()
  StartInput.l()
  StopInput.l()
  ResetInput.l()
  
  ProgramChange.l(Channel.b, Voice.b)
  NoteOn.l(Channel.b, Note.b, Velocity.b)
  NoteOff.l(Channel.b, Note.b, Velocity.b)
  NoteOffAlternate.l(Channel.b, Note.b)
  AllNotesOff.l(Channel.b)
  ChangeController.l(Channel.b, Controller.b, Value.b)
  ChannelPressure.l(Channel.b, Value.b)
  KeyAftertouch.l(Channe.b, Note.b, Value.b)
  PitchWheel.l(Channel.b, Value.w)
  SysEx.l(*SysEx, Length.l)
  ;}
  
  ;{ XG-Functions
  Master_Tune.l(Tune.l) ; 0..1024..2047
  Master_Volume_Realtime.l(Volume.l) ; 0..127
  Master_Volume.l(Volume.l) ; 0..127
  Master_Transpose.l(Transpose.l) ; 40..64.88
  Drum_Setup_1_Reset.l()
  Drum_Setup_2_Reset.l()
  XG_System_On.l()
  All_Parameter_Reset.l()
  TG300B_Reset.l()
  General_Midi_On.l()
  
  Bank_Select_MSB.l(Channel.b, Bank.b)
  Bank_Select_LSB.l(Channel.b, Bank.b)
  
  Volume.l(Channel.b, Volume.b)
  Panorama.l(Channel.b, Panorama.b)
  Modulation.l(Channel.b, Modulation.b)
  Expression.l(Channel.b, Expression.b)
  Reverb_Send_Level.l(Channel.b, Reverb.b)
  Chorus_Send_Level.l(Channel.b, Chorus.b)
  Variation_Effect_Send_Level.l(Channel.b, Variation_Effect.b)
  ;}
EndInterface
Structure PB_MIDI_Struc
  VTable.l
  
  fGetLastErrorText.l
  fGetLastErrorNr.l
  fKill.l
  
  ;{ MIDI-Functions
  fOpenOutputDevice.l
  fCloseOutputDevice.l
  fOpenInputDevice.l
  fCloseInputDevice.l
  fStartInput.l
  fStopInput.l
  fResetInput.l
  
  fProgramChange.l
  fNoteOn.l
  fNoteOff.l
  fNoteOffAlternate.l
  fAllNotesOff.l
  fChangeController.l
  fChannelPressure.l
  fKeyAftertouch.l
  fPitchWheel.l
  fSysEx.l
  ;}
  
  ;{ XG-Functions
  fMaster_Tune.l
  fMaster_Volume_Realtime.l
  fMaster_Volume.l
  fMaster_Transpose.l
  fDrum_Setup_1_Reset.l
  fDrum_Setup_2_Reset.l
  fXG_Systen_On.l
  fAll_Parameter_Reset.l
  fTG300B_Reset.l
  fGeneral_Midi_On.l
  
  fBank_Select_MSB.l
  fBank_Select_LSB.l
  
  fVolume.l
  fPanorama.l
  fModulation.l
  fExpression.l
  fReverb_Send_Level.l
  fChorus_Send_Level.l
  fVariation_Effect_Send_Level.l
  ;}
  
  ;Data
  OutDevice.l
  InDevice.l
  InCallback.l
  hOutDevice.l
  hInDevice.l
  LastError.l
  LastErrorFunc.l
EndStructure
Structure PB_MIDI_Msg
  Channel.b
  Note.b
  Velocity.b
  Null.b
EndStructure 

Enumeration
  #PB_MIDI_NoteOn
  #PB_MIDI_NoteOff
  #PB_MIDI_KeyAftertouch
  #PB_MIDI_ControllerChange
  #PB_MIDI_ProgramChange
  #PB_MIDI_ChannelPressure
  #PB_MIDI_PitchWheel
  #PB_MIDI_Unknown
EndEnumeration
#PB_XG_MSB_Normal_Voice = 0
#PB_XG_MSB_User_Voice = 63
#PB_XG_MSB_SFX_Voice = 64
#PB_XG_MSB_SFX_Kit = 126
#PB_XG_MSB_Drum_Kit = 127


Structure PB_MIDI_CBStruc
  Msg.l
  DataTyp.l
  Time.l
  MidiMessage.l
  Channel.b
  StructureUnion
    Controller.b
    Note.b
    Voice.b
  EndStructureUnion
  StructureUnion
    Velocity.b
    Value.b
  EndStructureUnion
  PitchWheel.w
  *SysEx
  SysExLength.l
EndStructure

#MIDIERR_BADOPENMODE = #MIDIERR_BASE + 6

;{ General MIDI

Procedure.s PB_MIDI_GetLastErrorText(*PM.PB_MIDI_Struc)
  Protected ErrorText.s
  ErrorText = "Error: "
  Select *PM\LastError
    Case #MMSYSERR_NOERROR : ErrorText + "No Error"
    Case #MIDIERR_NODEVICE : ErrorText + "No MIDI port was found. This error occurs only when the mapper is opened."
    Case #MMSYSERR_ALLOCATED : ErrorText + "The specified resource is already allocated."
    Case #MMSYSERR_BADDEVICEID : ErrorText + "The specified device identifier is out of range."
    Case #MMSYSERR_INVALPARAM : ErrorText + "The specified pointer or structure is invalid."
    Case #MMSYSERR_NOMEM : ErrorText + "The system is unable to allocate or lock memory."
    Case #MMSYSERR_INVALHANDLE : ErrorText + "The specified device handle is invalid."
    Case #MIDIERR_BADOPENMODE : ErrorText + "The application sent a message without a status byte to a stream handle."
    Case #MIDIERR_NOTREADY : ErrorText + "The hardware is busy with other data."
    Case #MIDIERR_STILLPLAYING : ErrorText + "Buffers are still in the queue."
    Case #MIDIERR_UNPREPARED : ErrorText + "The buffer pointed to by lpMidiOutHdr has not been prepared."
    
    Default : ErrorText + "Code " + Str(*PM\LastError)
  EndSelect
  ErrorText + #CRLF$ + "Function: "
  Select *PM\LastErrorFunc
    Case  0 : ErrorText + "No Function"
    Case  1 : ErrorText + "OpenOutptDevice"
    Case  2 : ErrorText + "OpenInputDevice"
    Case  3 : ErrorText + "StartInput"
    Case  4 : ErrorText + "StopInput"
    Case  5 : ErrorText + "ResetInput"
    Case  6 : ErrorText + "ProgramChange"
    Case  7 : ErrorText + "NoteOn"
    Case  8 : ErrorText + "NoteOff"
    Case  9 : ErrorText + "NoteOffAlternate"
    Case 10 : ErrorText + "AllNotesOff"
    Case 11 : ErrorText + "ChangeController"
    Case 12 : ErrorText + "ChannelPressure"
    Case 13 : ErrorText + "KeyAftertouch"
    Case 14 : ErrorText + "PitchWheel"
    Case 15 : ErrorText + "CloseOutputDevice"
    Case 16 : ErrorText + "CloseInputDevice"
    Case 17 : ErrorText + "SysEx(1)"
    Case 18 : ErrorText + "SysEx(2)"
    Case 19 : ErrorText + "SysEx(3)"
    Default : ErrorText + "Unknown"
  EndSelect
  *PM\LastError = #MMSYSERR_NOERROR
  *PM\LastErrorFunc = 0
  ProcedureReturn ErrorText
EndProcedure
Procedure PB_MIDI_GetLastErrorNr(*PM.PB_MIDI_Struc)
  Protected Error.l
  Error = *PM\LastError
  *PM\LastError = 0
  ProcedureReturn Error
EndProcedure

Procedure PB_MIDI_OpenOutputDevice(*PM.PB_MIDI_Struc, DeviceID.l)
  Protected Error.l
  Error = midiOutOpen_(@*PM\hOutDevice, DeviceID, 0, 0, 0)
  If Error = #MMSYSERR_NOERROR
    *PM\OutDevice = DeviceID
    ProcedureReturn #True
  Else
    *PM\LastErrorFunc = 1
    *PM\LastError = Error
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_CloseOutputDevice(*PM.PB_MIDI_Struc)
  Protected Error.l
  Error = midiOutClose_(*PM\hOutDevice)
  If Error = #MMSYSERR_NOERROR
    *PM\OutDevice = 0
    *PM\hOutDevice = 0
    ProcedureReturn #True
  Else
    *PM\LastErrorFunc = 15
    *PM\LastError = Error
    ProcedureReturn #False
  EndIf
EndProcedure

Procedure InCallback(*PM.PB_MIDI, *Msg.PB_MIDI_CBStruc)
  Protected Hex.s, a.l
  
  Select *Msg\Msg
    Case #MM_MIM_OPEN
      Debug "open"
      
    Case #MM_MIM_CLOSE
      Debug "close"
    
    Case #MM_MIM_DATA
      Select *Msg\DataTyp
        Case #PB_MIDI_NoteOn
          Debug "NoteOn: " + Str(*Msg\Note) + " [" + Str(*Msg\Velocity) + "] (" + Str(*Msg\Channel) + ")"
        Case #PB_MIDI_NoteOff
          Debug "NoteOff: " + Str(*Msg\Note) + " (" + Str(*Msg\Channel) + ")"
        Case #PB_MIDI_KeyAftertouch
        Case #PB_MIDI_ControllerChange
        Case #PB_MIDI_ProgramChange
          Debug "ProgramChange: " + Str(*Msg\Voice) + " (" + Str(*Msg\Channel) + ")"
        Case #PB_MIDI_ChannelPressure
        Case #PB_MIDI_PitchWheel
        Case #PB_MIDI_Unknown
      EndSelect
    
    Case #MM_MIM_LONGDATA
      Hex = ""
      For a = 1 To *Msg\SysExLength
        Hex = Hex + RSet(Hex(PeekB(*Msg\SysEx + a - 1) & $FF), 2, "0")
      Next
      Debug "longdata"
      Debug "SysEx: " + Hex
  EndSelect
EndProcedure

Procedure PB_MIDI_InCallback(hMidiIn.l, wMsg.l, *PM.PB_MIDI_Struc, dwMidiMessage.l, dwTimeStamp.l)
  Protected Status.l, Msg.PB_MIDI_CBStruc, *SysEx.MIDIHDR
  
  If *PM\InCallback = 0 : ProcedureReturn : EndIf
  
  Select wMsg
    Case #MM_MIM_OPEN
      Msg\Msg = wMsg
      CallFunctionFast(*PM\InCallback, *PM, @Msg)
    
    Case #MM_MIM_CLOSE
      Msg\Msg = wMsg
      CallFunctionFast(*PM\InCallback, *PM, @Msg)
      
    Case #MM_MIM_DATA
      Msg\Msg = wMsg
      Msg\Time = dwTimeStamp
      
      Select (dwMidiMessage & $F0) >> 4
        Case $8
          Msg\DataTyp = #PB_MIDI_NoteOn
          Msg\Channel = dwMidiMessage & $F
          Msg\Note = (dwMidiMessage >> 8) & $FF
          Msg\Velocity = (dwMidiMessage >> 16) & $FF
        
        Case $9
          If dwMidiMessage & $FF0000
            Msg\DataTyp = #PB_MIDI_NoteOn
          Else
            Msg\DataTyp = #PB_MIDI_NoteOff
          EndIf
          Msg\Channel = dwMidiMessage & $F
          Msg\Note = (dwMidiMessage >> 8) & $FF
          Msg\Velocity = (dwMidiMessage >> 16) & $FF
        
        Case $A
          Msg\DataTyp = #PB_MIDI_KeyAftertouch
          Msg\Channel = dwMidiMessage & $F
          Msg\Note = (dwMidiMessage >> 8) & $FF
          Msg\Value = (dwMidiMessage >> 16) & $FF
        
        Case $B
          Msg\DataTyp = #PB_MIDI_ControllerChange
          Msg\Channel = dwMidiMessage & $F
          Msg\Controller = (dwMidiMessage >> 8) & $FF
          Msg\Value = (dwMidiMessage >> 16) & $FF
        
        Case $C
          Msg\DataTyp = #PB_MIDI_ProgramChange
          Msg\Channel = dwMidiMessage & $F
          Msg\Voice = (dwMidiMessage >> 8) & $FF
        
        Case $D
          Msg\DataTyp = #PB_MIDI_ChannelPressure
          Msg\Channel = dwMidiMessage & $F
          Msg\Value = (dwMidiMessage >> 8) & $FF
          
        Case $E
          Msg\DataTyp = #PB_MIDI_PitchWheel
          Msg\Channel = dwMidiMessage & $F
          Msg\PitchWheel = (dwMidiMessage >> 16) & $FFFF
        
        Default
          Msg\DataTyp = #PB_MIDI_Unknown
      EndSelect
      CallFunctionFast(*PM\InCallback, *PM, @Msg)
    
    Case #MM_MIM_LONGDATA
      Msg\Msg = wMsg
      Msg\Time = dwTimeStamp
      *SysEx = dwMidiMessage
      Msg\SysExLength = *SysEx\dwBufferLength
      Msg\SysEx = *SysEx\lpData
      CallFunctionFast(*PM\InCallback, *PM, @Msg)
      
    Case #MM_MIM_ERROR
      Msg\Msg = wMsg
      Msg\Time = dwTimeStamp
      Msg\MidiMessage = dwMidiMessage
      CallFunctionFast(*PM\InCallback, *PM, @Msg)
    
    Case #MM_MIM_LONGERROR
      Msg\Msg = wMsg
      Msg\Time = dwTimeStamp
      *SysEx = dwMidiMessage
      Msg\SysExLength = *SysEx\dwBufferLength
      Msg\SysEx = *SysEx\lpData
      CallFunctionFast(*PM\InCallback, *PM, @Msg)
    
    Default
      Msg\Msg = #PB_MIDI_Unknown
  EndSelect
EndProcedure
Procedure PB_MIDI_OpenInputDevice(*PM.PB_MIDI_Struc, DeviceID.l, Callback.l)
  Protected Error.l
  
  Error = midiInOpen_(@*PM\hInDevice, DeviceID, @PB_MIDI_InCallback(), *PM, #CALLBACK_FUNCTION)
  If Error = #MMSYSERR_NOERROR
    *PM\InDevice = DeviceID
    *PM\InCallback = Callback
    ProcedureReturn #True
  Else
    *PM\LastErrorFunc = 2
    *PM\LastError = Error
    ProcedureReturn #False
  EndIf 
EndProcedure
Procedure PB_MIDI_CloseInputDevice(*PM.PB_MIDI_Struc)
  Protected Error.l
  Error = midiInClose_(*PM\hInDevice)
  If Error = #MMSYSERR_NOERROR
    *PM\InDevice = 0
    *PM\hInDevice = 0
    *PM\InCallback = 0
    ProcedureReturn #True
  Else
    *PM\LastErrorFunc = 16
    *PM\LastError = Error
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_StartInput(*PM.PB_MIDI_Struc)
  Protected Error.l
  
  Error = midiInStart_(*PM\hInDevice)
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastErrorFunc = 3
    *PM\LastError = Error
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_StopInput(*PM.PB_MIDI_Struc)
  Protected Error.l
  
  Error = midiInStop_(*PM\hInDevice)
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastErrorFunc = 4
    *PM\LastError = Error
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_ResetInput(*PM.PB_MIDI_Struc)
  Protected Error.l
  
  Error = midiInReset_(*PM\hInDevice)
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastErrorFunc = 5
    *PM\LastError = Error
    ProcedureReturn #False
  EndIf
EndProcedure

;Channel: 0-15
;Voice: 0-127
;Note: 0-127
;Controller: 0-127
;Value: 0-127
;Value von PitchWheel: 0-32768 (?)
Procedure PB_MIDI_ProgramChange(*PM.PB_MIDI_Struc, Channel.b, Voice.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $C0 + Channel
  Msg\Note = Voice
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekW(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 6
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_NoteOn(*PM.PB_MIDI_Struc, Channel.b, Note.b, Velocity.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $90 + Channel
  Msg\Note = Note
  Msg\Velocity = Velocity
  Msg\Null = 0
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 7
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_NoteOff(*PM.PB_MIDI_Struc, Channel.b, Note.b, Velocity.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $80 + Channel
  Msg\Note = Note
  Msg\Velocity = Velocity
  Msg\Null = 0
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 8
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_NoteOffAlternate(*PM.PB_MIDI_Struc, Channel.b, Note.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $90 + Channel
  Msg\Note = Note
  Msg\Velocity = 0
  Msg\Null = 0
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 9
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_AllNotesOff(*PM.PB_MIDI_Struc, Channel.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $B0 + Channel
  Msg\Note = $7B
  Msg\Velocity = 0
  Msg\Null = 0
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 10
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_ChangeController(*PM.PB_MIDI_Struc, Channel.b, Controller.b, Value.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $B0 + Channel
  Msg\Note = Controller
  Msg\Velocity = Value
  Msg\Null = 0
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 11
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_ChannelPressure(*PM.PB_MIDI_Struc, Channel.b, Value.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $D0 + Channel
  Msg\Note = Value
  Msg\Velocity = 0
  Msg\Null = 0
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 12
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_KeyAftertouch(*PM.PB_MIDI_Struc, Channel.b, Note.b, Value.b)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $A0 + Channel
  Msg\Note = Note
  Msg\Velocity = Value
  Msg\Null = 0
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 12
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_PitchWheel(*PM.PB_MIDI_Struc, Channel.b, Value.w)
  Protected Msg.PB_MIDI_Msg, Error.l
  Msg\Channel = $E0 + Channel
  Msg\Null = 0
  PokeW(@Msg, Value)
  Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
  If Error = #MMSYSERR_NOERROR
    ProcedureReturn #True
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 12
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure PB_MIDI_SysEx(*PM.PB_MIDI_Struc, *SysEx, Length.l)
  Protected SysEx.MIDIHDR, Error.l
  SysEx\lpData = *SysEx
  SysEx\dwBufferLength = Length
  SysEx\dwBytesRecorded = Length
  
  Error = midiOutPrepareHeader_(*PM\hOutDevice, @SysEx, SizeOf(MIDIHDR))
  If Error = #MMSYSERR_NOERROR
    Error = midiOutLongMsg_(*PM\hOutDevice, @SysEx, SizeOf(MIDIHDR))
    If Error = #MMSYSERR_NOERROR
      Repeat
        Error = midiOutUnprepareHeader_(*PM\hOutDevice, @SysEx, SizeOf(MIDIHDR))
        If Error = #MMSYSERR_NOERROR
          Break
        ElseIf Error <> #MIDIERR_STILLPLAYING
          *PM\LastError = Error
          *PM\LastErrorFunc = 19
          ProcedureReturn #False
        EndIf
      ForEver
      ProcedureReturn #True
    Else
      *PM\LastError = Error
      *PM\LastErrorFunc = 18
      ProcedureReturn #False
    EndIf
  Else
    *PM\LastError = Error
    *PM\LastErrorFunc = 17
    ProcedureReturn #False
  EndIf
  
EndProcedure
;}

;{ XG 
Procedure PB_XG_Master_Tune(*PM.PB_MIDI, Tune.l)
  ;F0,43,10,4C,00,00,00,0W,0X,0Y,0Z,F7
  Protected *SysEx, Result.l
  Result = #False
  *SysEx = AllocateMemory(12)
  If *SysEx
    PokeL(*SysEx    , $4C1043F0)
    PokeB(*SysEx +  7, (Tune >> 12) & $F)
    PokeB(*SysEx +  8, (Tune >> 8 ) & $F)
    PokeB(*SysEx +  9, (Tune >> 4 ) & $F)
    PokeB(*SysEx + 10, Tune & $F)
    PokeB(*SysEx + 11, $F7)
    Result = *PM\SysEx(*SysEx, 12)
    FreeMemory(*SysEx)
  EndIf
  ProcedureReturn Result
EndProcedure
Procedure PB_XG_Master_Volume_Realtime(*PM.PB_MIDI, Volume.l)
  ;F0,7F,7F,04,01,00,XX,F7
  Protected *SysEx, Result.l
  Result = #False
  *SysEx = AllocateMemory(8)
  If *SysEx
    PokeL(*SysEx    , $047F7FF0)
    PokeW(*SysEx + 4, $0001)
    PokeB(*SysEx + 6, Volume & $7F)
    PokeB(*SysEx + 7, $F7)
    Result = *PM\SysEx(*SysEx, 8)
    FreeMemory(*SysEx)
  EndIf
  ProcedureReturn Result
EndProcedure
Procedure PB_XG_Master_Volume(*PM.PB_MIDI, Volume.l)
  ;F0,43,10,4C,00,00,04,XX,F7
  Protected *SysEx, Result.l
  Result = #False
  *SysEx = AllocateMemory(9)
  If *SysEx
    PokeL(*SysEx    , $4C1043F0)
    PokeL(*SysEx + 4, $040000)
    PokeB(*SysEx + 7, Volume & $7F)
    PokeB(*SysEx + 8, $F7)
    Result = *PM\SysEx(*SysEx, 9)
    FreeMemory(*SysEx)
  EndIf
  ProcedureReturn Result
EndProcedure
Procedure PB_XG_Master_Transpose(*PM.PB_MIDI, Transpose.l)
  ;F0,43,10,4C,00,00,06,XX,F7
  Protected *SysEx, Result.l
  Result = #False
  *SysEx = AllocateMemory(9)
  If *SysEx
    PokeL(*SysEx    , $4C1043F0)
    PokeL(*SysEx + 4, $00060000)
    PokeB(*SysEx + 7, Transpose & $FF)
    PokeB(*SysEx + 8, $F7)
    Result = *PM\SysEx(*SysEx, 9)
    FreeMemory(*SysEx)
  EndIf
  ProcedureReturn Result
EndProcedure
Procedure PB_XG_Drum_Setup_1_Reset(*PM.PB_MIDI)
  ;F0,43,10,4C,00,00,7D,00,F7
  Protected *SysEx, Result.l
  Result = #False
  *SysEx = AllocateMemory(9)
  If *SysEx
    PokeL(*SysEx    , $4C1043F0)
    PokeL(*SysEx + 4, $007D0000)
    PokeB(*SysEx + 8, $F7)
    Result = *PM\SysEx(*SysEx, 9)
    FreeMemory(*SysEx)
  EndIf
  ProcedureReturn Result
EndProcedure
Procedure PB_XG_Drum_Setup_2_Reset(*PM.PB_MIDI)
  ;F0,43,10,4C,00,00,7D,01,F7
  Protected *SysEx, Result.l
  Result = #False
  *SysEx = AllocateMemory(9)
  If *SysEx
    PokeL(*SysEx    , $4C1043F0)
    PokeL(*SysEx + 4, $017D0000)
    PokeB(*SysEx + 8, $F7)
    Result = *PM\SysEx(*SysEx, 9)
    FreeMemory(*SysEx)
  EndIf
  ProcedureReturn Result
EndProcedure
Procedure PB_XG_XG_System_On(*PM.PB_MIDI)
  ;F0,43,10,4C,00,00,7E,00,F7
  Protected *SysEx, Result.l
  Result = #False
  *SysEx = AllocateMemory(9)
  If *SysEx
    PokeL(*SysEx    , $4C1043F0)
    PokeL(*SysEx + 4, $007E0000)
    PokeB(*SysEx + 8, $F7)
    Result = *PM\SysEx(*SysEx, 9)
    FreeMemory(*SysEx)
  EndIf
  ProcedureReturn Result
EndProcedure
Procedure PB_XG_All_Parameter_Reset(*PM.PB_MIDI)
  ;F0,43,10,4C,00,00,7F,00,F7
  Protected *SysEx, Result.l
  Result = #False
  *SysEx = AllocateMemory(9)
  If *SysEx
    PokeL(*SysEx    , $4C1043F0)
    PokeL(*SysEx + 4, $007F0000)
    PokeB(*SysEx + 8, $F7)
    Result = *PM\SysEx(*SysEx, 9)
    FreeMemory(*SysEx)
  EndIf
  ProcedureReturn Result
EndProcedure
Procedure PB_XG_TG300B_Reset(*PM.PB_MIDI)
  ;F0,41,10,42,12,40,00,7F,00,41,F7
  Protected *SysEx, Result.l
  Result = #False
  *SysEx = AllocateMemory(11)
  If *SysEx
    PokeL(*SysEx     , $421041F0)
    PokeL(*SysEx +  4, $7F004012)
    PokeB(*SysEx +  8, $00)
    PokeB(*SysEx +  9, $41)
    PokeB(*SysEx + 10, $F7)
    Result = *PM\SysEx(*SysEx, 11)
    FreeMemory(*SysEx)
  EndIf
  ProcedureReturn Result
EndProcedure
Procedure PB_XG_General_MIDI_On(*PM.PB_MIDI)
  ;F0,7E,7F,09,01,F7
  Protected *SysEx, Result.l
  Result = #False
  *SysEx = AllocateMemory(6)
  If *SysEx
    PokeL(*SysEx    , $097F7EF0)
    PokeW(*SysEx + 4, $F701)
    Result = *PM\SysEx(*SysEx, 6)
    FreeMemory(*SysEx)
  EndIf
  ProcedureReturn Result
EndProcedure

Procedure PB_XG_Bank_Select_MSB(*PM.PB_MIDI, Channel.b, Bank.b)
  ProcedureReturn *PM\ChangeController(Channel, 0, Bank)
EndProcedure
Procedure PB_XG_Bank_Select_LSB(*PM.PB_MIDI, Channel.b, Bank.b)
  ProcedureReturn *PM\ChangeController(Channel, 32, Bank)
EndProcedure

Procedure PB_XG_Volume(*PM.PB_MIDI, Channel.b, Volume.b)
  ProcedureReturn *PM\ChangeController(Channel, 7, Volume)
EndProcedure
Procedure PB_XG_Panorama(*PM.PB_MIDI, Channel.b, Panorama.b)
  ProcedureReturn *PM\ChangeController(Channel, 10, Panorama)
EndProcedure
Procedure PB_XG_Modulation(*PM.PB_MIDI, Channel.b, Modulation.b)
  ProcedureReturn *PM\ChangeController(Channel, 1, Modulation)
EndProcedure
Procedure PB_XG_Expression(*PM.PB_MIDI, Channel.b, Expression.b)
  ProcedureReturn *PM\ChangeController(Channel, 11, Expression)
EndProcedure
Procedure PB_XG_Reverb_Send_Level(*PM.PB_MIDI, Channel.b, Reverb.b)
  ProcedureReturn *PM\ChangeController(Channel, 91, Reverb)
EndProcedure
Procedure PB_XG_Chorus_Send_Level(*PM.PB_MIDI, Channel.b, Chorus.b)
  ProcedureReturn *PM\ChangeController(Channel, 93, Chorus)
EndProcedure
Procedure PB_XG_Variation_Effect_Send_Level(*PM.PB_MIDI, Channel.b, Variation_Effect.b)
  ProcedureReturn *PM\ChangeController(Channel, 94, Variation_Effect)
EndProcedure
;}

Procedure PB_MIDI_Kill(*PM.PB_MIDI_Struc)
  While midiInClose_(*PM\hInDevice) = #MIDIERR_STILLPLAYING : Wend 
  While midiOutClose_(*PM\hOutDevice) = #MIDIERR_STILLPLAYING : Wend 
  FreeMemory(*PM)
  ProcedureReturn #True
EndProcedure
Procedure PB_MIDI_Create()
  Protected *PM.PB_MIDI_Struc
  
  *PM = AllocateMemory(SizeOf(PB_MIDI_Struc))
  If *PM = 0 : ProcedureReturn #False : EndIf
  *PM\VTable = *PM + 4
  ;{ MIDI-Functions
  *PM\fGetLastErrorText       = @PB_MIDI_GetLastErrorText()
  *PM\fGetLastErrorNr         = @PB_MIDI_GetLastErrorNr()
  *PM\fKill                   = @PB_MIDI_Kill()
  *PM\fOpenOutputDevice       = @PB_MIDI_OpenOutputDevice()
  *PM\fOpenInputDevice        = @PB_MIDI_OpenInputDevice()
  *PM\fStartInput             = @PB_MIDI_StartInput()
  *PM\fStopInput              = @PB_MIDI_StopInput()
  *PM\fResetInput             = @PB_MIDI_ResetInput()
  *PM\fProgramChange          = @PB_MIDI_ProgramChange()
  *PM\fNoteOn                 = @PB_MIDI_NoteOn()
  *PM\fNoteOff                = @PB_MIDI_NoteOff()
  *PM\fNoteOffAlternate       = @PB_MIDI_NoteOffAlternate()
  *PM\fAllNotesOff            = @PB_MIDI_AllNotesOff()
  *PM\fChangeController       = @PB_MIDI_ChangeController()
  *PM\fChannelPressure        = @PB_MIDI_ChannelPressure()
  *PM\fKeyAftertouch          = @PB_MIDI_KeyAftertouch()
  *PM\fPitchWheel             = @PB_MIDI_PitchWheel()
  *PM\fSysEx                  = @PB_MIDI_SysEx()
  ;}
  
  ;{ XG-Functions
  *PM\fMaster_Tune            = @PB_XG_Master_Tune()
  *PM\fMaster_Volume_Realtime = @PB_XG_Master_Volume_Realtime()
  *PM\fMaster_Volume          = @PB_XG_Master_Volume()
  *PM\fMaster_Transpose       = @PB_XG_Master_Transpose()
  *PM\fDrum_Setup_1_Reset     = @PB_XG_Drum_Setup_1_Reset()
  *PM\fDrum_Setup_2_Reset     = @PB_XG_Drum_Setup_2_Reset()
  *PM\fXG_Systen_On           = @PB_XG_XG_System_On()
  *PM\fAll_Parameter_Reset    = @PB_XG_All_Parameter_Reset()
  *PM\fTG300B_Reset           = @PB_XG_TG300B_Reset()
  *PM\fGeneral_Midi_On        = @PB_XG_General_MIDI_On()
  
  *PM\fBank_Select_MSB        = @PB_XG_Bank_Select_MSB()
  *PM\fBank_Select_LSB        = @PB_XG_Bank_Select_LSB()
  
  *PM\fVolume                 = @PB_XG_Volume()
  *PM\fPanorama               = @PB_XG_Panorama()
  *PM\fModulation             = @PB_XG_Modulation()
  *PM\fExpression             = @PB_XG_Expression()
  *PM\fReverb_Send_Level      = @PB_XG_Reverb_Send_Level()
  *PM\fChorus_Send_Level      = @PB_XG_Chorus_Send_Level()
  *PM\fVariation_Effect_Send_Level = @PB_XG_Variation_Effect_Send_Level()
  ;}
  
  ProcedureReturn *PM
EndProcedure

Procedure PB_MIDI_Requester(*OutDevice.l, *InDevice.l) 
  Protected WinID.l
  Protected List1.l, List2.l, But1.l, But2.l, Txt1.l, Txt2.l, Txt3.l, Txt4.l
  Protected MaxOutDev.l, InfoOut.MIDIOUTCAPS, InDev.l, OutDev.l, Quit.l, Ok.l, EventID.l, a.l
  Protected Width.l, Column.l, Offset.l
  
  #MOD_WAVETABLE = 6 
  #MOD_SWSYNTH = 7 
  #MIDIRequ_InSet = 2 
  #MIDIRequ_OutSet = 1 

  Width = 400 
  WinID = OpenWindow(#PB_Any, 0, 0, Width, 270, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "MIDI-Requester") 
  If WinID
    If CreateGadgetList(WindowID(WinID)) 
      Column = (Width - 20) / 2 
      Offset = (Width / 2) + 5 
      
      TextGadget(#PB_Any, 5, 5, Column, 18, "Output-Device:", #PB_Text_Center | #PB_Text_Border) 
      List1 = ListViewGadget(#PB_Any, 5, 23, Column, 100) 
        MaxOutDev = midiOutGetNumDevs_() 
        If MaxOutDev 
          For a = -1 To MaxOutDev - 1 
            midiOutGetDevCaps_(a, InfoOut, SizeOf(MIDIOUTCAPS)) 
            AddGadgetItem(List1, -1, PeekS(@InfoOut\szPname[0], 32)) 
          Next 
        Else 
          AddGadgetItem(List1, -1, "(no output device)") 
          DisableGadget(List1, 1) 
        EndIf 
      If *OutDevice = 0 : DisableGadget(List1, 1) : EndIf
      
      TextGadget(#PB_Any, Offset, 5, Column, 18, "Input-Device:", #PB_Text_Center | #PB_Text_Border) 
      List2 = ListViewGadget(#PB_Any, Offset, 23, Column, 100) 
        MaxInDev.l = midiInGetNumDevs_() 
        InfoIn.MIDIINCAPS 
        If MaxInDev 
          For a = 0 To MaxInDev - 1 
            midiInGetDevCaps_(a, InfoIn, SizeOf(MIDIINCAPS)) 
            AddGadgetItem(List2, -1, PeekS(@InfoIn\szPname[0], 32)) 
          Next 
        Else 
          AddGadgetItem(List2, -1, "(no input device)") 
          DisableGadget(List2, 1) 
        EndIf 
      If *InDevice = 0 : DisableGadget(List2, 1) : EndIf
      
      But1 = ButtonGadget(#PB_Any, 5, 240, Column, 24, "&OK") 
      But2 = ButtonGadget(#PB_Any, Offset, 240, Column, 24, "&Cancel") 
      
      Frame3DGadget(#PB_Any, 5, 130, Width - 10, 100, "Info of Output-Device", 0) 
       Txt1 = TextGadget(#PB_Any, 10, 145, Width - 20, 18, "Version:") 
       Txt2 = TextGadget(#PB_Any, 10, 165, Width - 20, 18, "Technology:") 
       Txt3 = TextGadget(#PB_Any, 10, 185, Width - 20, 18, "Max. Voices:") 
       Txt4 = TextGadget(#PB_Any, 10, 205, Width - 20, 18, "Polyphonie:") 
      
      OutDev = 0 
      InDev = 0 
      Quit = #False 
      Ok = #False 
      Repeat 
        If GetGadgetState(List1) > -1 Or GetGadgetState(List2) > -1 
          DisableGadget(But1, 0) 
        Else 
          DisableGadget(But1, 1) 
        EndIf 
        
        If InDev <> GetGadgetState(List2) 
          InDev = GetGadgetState(List2) 
        EndIf 
        
        If GetGadgetState(List1) <> OutDev 
          OutDev = GetGadgetState(List1) 
          midiOutGetDevCaps_(OutDev - 1, InfoOut, SizeOf(MIDIOUTCAPS)) 
          SetGadgetText(Txt1, "Version: " + Str(InfoOut\vDriverVersion >> 8) + "." + Str(InfoOut\vDriverVersion & FF)) 
          Select InfoOut\wTechnology 
            Case #MOD_MIDIPORT :  TmpS.s = "Hardware Port" 
            Case #MOD_SYNTH :     TmpS.s = "Synthesizer" 
            Case #MOD_SQSYNTH :   TmpS.s = "Square Wave Synthesizer" 
            Case #MOD_FMSYNTH :   TmpS.s = "FM Synthesizer" 
            Case #MOD_MAPPER :    TmpS.s = "Microsoft MIDI Mapper" 
            Case #MOD_WAVETABLE : TmpS.s = "Hardware Wavetable Synthesizer" 
            Case #MOD_SWSYNTH :   TmpS.s = "Software Synthesizer" 
            Default: TmpS.s = "(Error Code " + Str(InfoOut\wTechnology) + ")" 
          EndSelect 
          SetGadgetText(Txt2, "Technology: " + TmpS) 
          If InfoOut\wVoices = 0 : TmpS.s = "inf" : Else : TmpS.s = Str(InfoOut\wVoices) : EndIf 
          SetGadgetText(Txt3, "Max. Voices: " + TmpS) 
          If InfoOut\wNotes = 0 : TmpS.s = "inf" : Else : TmpS.s = Str(InfoOut\wNotes) : EndIf 
          SetGadgetText(Txt4, "Polyphonie: " + TmpS) 
        EndIf 
        
        EventID = WaitWindowEvent() 
        Select EventID 
          Case #PB_EventCloseWindow 
            Quit = #True 
            Ok = #False 
          Case #PB_EventGadget 
            Select EventGadgetID() 
              Case But1 
                If *OutDevice : PokeL(*OutDevice, OutDev - 1) : EndIf
                If *InDevice : PokeL(*InDevice, InDev)  : EndIf
                Quit = #True 
                Ok = 3 
                If (OutDev = -1 Or CountGadgetItems(List1) = 0) And Ok & #MIDIRequ_OutSet : Ok ! #MIDIRequ_OutSet : EndIf 
                If (InDev = -1 Or CountGadgetItems(List2) = 0) And Ok & #MIDIRequ_InSet : Ok ! #MIDIRequ_InSet : EndIf 
              Case But2
                Quit = #True 
                Ok = #False 
            EndSelect 
        EndSelect 
      Until Quit 
      CloseWindow(WinID) 
      ProcedureReturn Ok 
    EndIf 
  EndIf 
  ProcedureReturn #False
EndProcedure 

If PB_MIDI_Requester(@OutDevice.l, @InDevice.l) = 0 : End : EndIf

*midi.PB_MIDI = PB_MIDI_Create()
If *midi\OpenOutputDevice(OutDevice) = 0 : Debug  *midi\GetLastErrorText() : EndIf

OpenConsole()
PrintN("Start")
*midi\XG_System_On()
*midi\ProgramChange(0, 5)

For a.l = 1 To 127 Step 25
  *midi\NoteOn(0, 60, 127)
  Print(Str(a) + " ")
  *midi\Reverb_Send_Level(0, a)
  Delay(200)
  *midi\NoteOff(0, 60, 0)
  Delay(1000)
Next


PrintN("")
PrintN("Ende")
Input()
CloseConsole()

*midi\Kill()
Den nächsten Code lade ich dann auf meinen WebSpace hoch, sonst wird das hier so unübersichtlich. :wink: :mrgreen:
Benutzeravatar
AndyX
Beiträge: 1272
Registriert: 17.12.2004 20:10
Wohnort: Niederösterreich
Kontaktdaten:

Beitrag von AndyX »

:shock: einfach nur geil!

Danke!
Antworten