|
Antwort |
EWeiss
|
#81
Zitat:
Zur Info: Besonders beim Senden von SysEx sind Expander/Soundmodule manchmal für ein paar Millisekunden "tot", d.h. reagieren nicht auf weitere Midi-Events.
Zitat:
Werde dann berichten. Das generelle Problem ist nämlich, dass es keine (mir bekannten) guten Midi-Komponenten mit Source für Delphi gibt. Alle haben sie irgendwo eine kleine Macke, und die meisten davon werden sowieso nicht weiter entwickelt. Zur Not muss ich selber mal ganz von vorne anfangen. Wenn nur die Zeit dafür da wäre
Bedenke das ist ein Freeware Projekt ist also nicht ausgelegt für den Professionellen Bereich. Und nein ich möchte mir das nicht antun meine Zeit (gegen Bares) in das Projekt zu stecken es würde sich einfach nicht lohnen. Ich ändere etwas dran wenn ich zeit finde oder Lust dazu habe das soll nicht in MÜSSEN ausarten gruss Geändert von EWeiss (24. Mai 2015 um 17:21 Uhr) |
Zitat |
|
#82
Hallo, sorry für mein Deutsch übersetzt mit Google Trans.
Ich hatte auch Probleme mit den SysEx und ich schaffte es, durch Änderung der Code TMidiPlayer2.pas beheben. Ich bin kein professioneller Programmierer, aber jetzt SysEx-Funktion. Ich lege Bearbeitungsverfahren TMidiDriver.DoOnMidiTimer. Ich habe Änderungen in Version 0.9.5.1 durchgeführt. Sicher wird es auch in den folgenden Versionen. Änderungen werden durch (****** JV *****) hervorgehoben. Einen schönen Tag noch. wolfmusic Modifizierten Code:
Delphi-Quellcode:
procedure TMidiDriver.DoOnMidiTimer;
var (****************************JV ******************************************) i, n: Integer; (****************************JV ******************************************) TickTime: LongWord; DeltaTime: LongWord; AMidiTrack: TMidiTrack; pEvent: pMidiEvent; EventCode: byte; ChannelNo: byte; ActiveNoteRemains: boolean; OutNote: byte; EventPositon: LongWord; (****************************JV ******************************************) SysExJv: array of Byte; (*Word*) (****************************JV ******************************************) begin if not Assigned(MidiFile) then Exit; TickTime := GetTickCount; if LastOutputTime = 0 then begin DeltaTime := TickTime - FStartTime; FCurrentTime := round(DeltaTime * FSpeed); end else begin DeltaTime := TickTime - LastOutputTime; FCurrentTime := FCurrentTime + round(DeltaTime * FSpeed); end; LastOutputTime := TickTime; FCurrentPos := MidiFile.Time2TickPos(FCurrentTime); // I have found a MIDI file which does not have the end of track mark. // Following sentences are for the case to stop playing forcibly. if FCurrentTime > (MidiFile.Duration + 300) then begin Suspend := true; // to prohibit calling DoOnMidiTimer in PlayThread if FStepMode then SendMessage(FPlayerHandle, WM_MIDI_EndOfTrack, 0, 1) else PostMessage(FPlayerHandle, WM_MIDI_EndOfTrack, 0, 1); exit; end; for i := 0 to MidiFile.TrackCount - 1 do begin AMidiTrack := MidiFile.GetTrack(i); if not AMidiTrack.EndOfTrack then with AMidiTrack do begin while (AMidiTrack.PlayPos < AMidiTrack.EventCount) do begin pEvent := GetEvent(PlayPos); EventPositon := pEvent^.Positon; if (Round(FCurrentPos) <= EventPositon) then break; if PEvent.Event = $FF then ProcessEvent(i, pEvent) else if AMidiTrack.Active then begin EventCode := pEvent^.Event and $F0; ChannelNo := pEvent^.Event and $0F; if pEvent^.Msg = '' then // Not a System Exclusive Message ? begin ActiveNoteRemains := IsActiveNote(ChannelNo); // The note number for drum channel defines the different percussion instruments, // So, we should not change that. if ChannelNo = DrumChannel then // Drum channel ? OutNote := pEvent^.Data1 // Output the adjusted note number for the Note On, Note Off and Note Aftertouch Events // by FPitch value. else if (EventCode = $80) or (EventCode = $90) or (EventCode = $A0) then begin OutNote := pEvent^.Data1 + FPitch; if (EventCode = $80) or ((EventCode = $90) and (pEvent^.Data2 = 0)) then begin if FChannelState[ChannelNo] then DeleteConvRecord(pEvent^.Event and $0F, pEvent^.Data1, OutNote) end else if FChannelState[ChannelNo] then AddConvRecord(pEvent^.Event and $0F, pEvent^.Data1, OutNote); end else OutNote := pEvent^.Data1; if FChannelState[ChannelNo] then MidiOut.PutShort(pEvent^.Event, OutNote, pEvent^.Data2) else begin if ActiveNoteRemains then begin // $B0 + ChannelNo : Control change, 123 : All Notes Off MidiOut.PutShort($B0 + ChannelNo, 123, pEvent^.Data2); ClearChannelRecord(ChannelNo); end; // Activate following 2 lines if we want to process Control change messages and // Program change messages regardless of channel's On/Off state. if (EventCode = $B0) or (EventCode = $C0) then MidiOut.PutShort(pEvent^.Event, pEvent^.Data1, pEvent^.Data2); end; end else if (not NoExclusiveMsg) then // if FChannelState[ChannelNo] then (********************************************JV ******************************************) // original MidiOut.PutLong(pAnsiChar(pEvent^.Msg), Length(pEvent^.Msg)); if (EventCode = $F0) and (pEvent^.Msg <> '') then {if pEvent^.Msg <> '' then} begin SetLength(SysExJv, 0); SetLength(SysExJv, Length(pEvent^.Msg) + 1); SysExJv[0]:= $F0; for n:= 0 to Length(pEvent^.Msg) - 1 do begin SysExJv[N + 1]:= Byte(pEvent^.Msg[N + 1]); end; MidiOut.PutLong(@SysExJv[0], Length(SysExJv)); end; (********************************************JV ******************************************) // if FChannelState[ChannelNo] then if FChannelState[ChannelNo] or (pEvent^.Msg <> '') or (EventCode = $B0) or (EventCode = $C0) then if FStepMode then SendMessage(FPlayerHandle, WM_MIDI_Event, i, integer(pEvent)) else PostMessage(FPlayerHandle, WM_MIDI_Event, i, integer(pEvent)); end; // Messages for meta event are posted in the procedure ProcessEvent. { if FStepMode then SendMessage(FPlayerHandle, WM_MIDI_Event, i, integer(pEvent)) else PostMessage(FPlayerHandle, WM_MIDI_Event, i, integer(pEvent)); } PlayPos := PlayPos + 1; end; end; end; if FStepMode then SendMessage(FPlayerHandle, WM_MIDI_PosUpdate, FCurrentTime, FCurrentPos) else PostMessage(FPlayerHandle, WM_MIDI_PosUpdate, FCurrentTime, FCurrentPos); end; Geändert von wolfmusic (31. Mai 2015 um 10:54 Uhr) |
Zitat |
EWeiss
|
#83
Danke!
Ersetzt mal bitte die procedure TMidiDriver.DoOnMidiTimer in der MidiPlayer2.pas
Delphi-Quellcode:
Sollten dann immer noch Probleme auftauchen in Verbindung mit den Sytem Exclusiven Messagen..
procedure TMidiDriver.DoOnMidiTimer;
var i: Integer; TickTime: LongWord; DeltaTime: LongWord; AMidiTrack: TMidiTrack; pEvent: pMidiEvent; EventCode: byte; ChannelNo: byte; ActiveNoteRemains: boolean; OutNote: byte; EventPositon: LongWord; tmpSuspend: boolean; SysExMsg: AnsiString; begin if not Assigned(MidiFile) then Exit; TickTime := GetTickCount; if LastOutputTime = 0 then begin DeltaTime := TickTime - FStartTime; FCurrentTime := round(DeltaTime * FSpeed); end else begin DeltaTime := TickTime - LastOutputTime; FCurrentTime := FCurrentTime + round(DeltaTime * FSpeed); end; LastOutputTime := TickTime; FCurrentPos := MidiFile.Time2TickPos(FCurrentTime); if FFirePosition > 0 then // if we set to fire on specified Position begin if FCurrentPos >= FFirePosition then begin if not FFired then // to suppress multiple events on specified Position begin FFired := true; // exit if return value is not 0 if SendMessage(FPlayerHandle, WM_MIDI_ArrivedAtFirePos, FCurrentTime, FCurrentPos) <> 0 then exit; end; end else if FFired then FFired := false; end; // Set back to the start position of specified interval, when player reachs the end position // of specified interval, if we activated repeat-interval function. tmpSuspend := false; if FRepeatSection then if FCurrentPos >= FEndPos then begin tmpSuspend := true; Suspend := true; MidiOut.SentAllNotesOff; SetCurrentPos(FBeginPos); // PostMessage(FPlayerHandle, WM_MIDI_PosChangeByRepeat, FBeginPos, FCurrentPos); end; // I have found a MIDI file which does not have the end of track mark. // Following sentences are for the case to stop playing forcibly. if FCurrentTime > (MidiFile.Duration + 300) then begin Suspend := true; // to prohibit calling DoOnMidiTimer in PlayThread if FStepMode then SendMessage(FPlayerHandle, WM_MIDI_EndOfTrack, 0, 1) else PostMessage(FPlayerHandle, WM_MIDI_EndOfTrack, 0, 1); exit; end; for i := 0 to MidiFile.TrackCount - 1 do begin AMidiTrack := MidiFile.GetTrack(i); if not AMidiTrack.EndOfTrack then with AMidiTrack do begin while (AMidiTrack.PlayPos < AMidiTrack.EventCount) do begin pEvent := GetEvent(PlayPos); EventPositon := pEvent^.Positon; if (Round(FCurrentPos) <= EventPositon) then break; // Got the verse change event ? // ( * This is not a standard MIDI event, It's just to support custom specification) if (pEvent^.Event = $B0) and (pEvent^.Data1 = $14) then // verse change event ? begin if FVerseNum <> pEvent^.Data2 then begin PostMessage(FPlayerHandle, WM_MIDI_VerseChange, FVerseNum, pEvent^.Data2); FVerseNum := pEvent^.Data2; end; PlayPos := PlayPos + 1; continue; end; if PEvent.Event = $FF then ProcessEvent(i, pEvent) else if AMidiTrack.Active then begin EventCode := pEvent^.Event and $F0; ChannelNo := pEvent^.Event and $0F; if pEvent^.Msg = '' then // Not a System Exclusive Message ? begin ActiveNoteRemains := IsActiveNote(ChannelNo); // The note number for drum channel defines the different percussion instruments, // So, we should not change that. if ChannelNo = DrumChannel then // Drum channel ? OutNote := pEvent^.Data1 // Output the adjusted note number for the Note On, Note Off and Note Aftertouch Events // by FPitch value. else if (EventCode = $80) or (EventCode = $90) or (EventCode = $A0) then begin OutNote := pEvent^.Data1 + FPitch; if (EventCode = $80) or ((EventCode = $90) and (pEvent^.Data2 = 0)) then begin if FChannelState[ChannelNo] then DeleteConvRecord(pEvent^.Event and $0F, pEvent^.Data1, OutNote) end else if FChannelState[ChannelNo] then AddConvRecord(pEvent^.Event and $0F, pEvent^.Data1, OutNote); end else OutNote := pEvent^.Data1; if FChannelState[ChannelNo] then begin // if event code is Bank select or Program change, Skip if pre-assigned instrument // should be applied if (EventCode <> $B0) and (EventCode <> $C0) then MidiOut.PutShort(pEvent^.Event, OutNote, pEvent^.Data2) else if CanOutput(pEvent) then MidiOut.PutShort(pEvent^.Event, OutNote, pEvent^.Data2); end else begin if ActiveNoteRemains then begin // $B0 + ChannelNo : Control change, 123 : All Notes Off MidiOut.PutShort($B0 + ChannelNo, 123, pEvent^.Data2); ClearChannelRecord(ChannelNo); end; // Activate following 2 lines if we want to process Control change messages and // Program change messages regardless of channel's On/Off state. if (EventCode = $B0) or (EventCode = $C0) then // if event code is Bank select or Program change, Skip if pre-assigned instrument // should be applied if CanOutput(pEvent) then MidiOut.PutShort(pEvent^.Event, pEvent^.Data1, pEvent^.Data2); end; end else if (not NoExclusiveMsg) then // for (pEvent^.Msg <> '') if (EventCode = $F0) or (EventCode = $F7) then // $F7 - used as a Message continuation mark begin // if FChannelState[ChannelNo] then // MidiOut.PutLong(pAnsiChar(pEvent^.Msg), Length(pEvent^.Msg)); // * missed event code // * Bug fix : correction for missed event code (01 Jun 2015) SysExMsg := AnsiChar(EventCode) + pEvent^.Msg; MidiOut.PutLong(@SysExMsg[1], Length(SysExMsg)); end; // if FChannelState[ChannelNo] then if (FChannelState[ChannelNo] or (pEvent^.Msg <> '')) and (EventCode <> $B0) and (EventCode <> $C0) then begin if FStepMode then SendMessage(FPlayerHandle, WM_MIDI_Event, i, integer(pEvent)) else PostMessage(FPlayerHandle, WM_MIDI_Event, i, integer(pEvent)); end else if (EventCode = $B0) or (EventCode = $C0) then if CanOutput(pEvent) then if FStepMode then SendMessage(FPlayerHandle, WM_MIDI_Event, i, integer(pEvent)) else PostMessage(FPlayerHandle, WM_MIDI_Event, i, integer(pEvent)); end; // Messages for meta event are posted in the procedure ProcessEvent. { if FStepMode then SendMessage(FPlayerHandle, WM_MIDI_Event, i, integer(pEvent)) else PostMessage(FPlayerHandle, WM_MIDI_Event, i, integer(pEvent)); } PlayPos := PlayPos + 1; end; end; end; if FStepMode then SendMessage(FPlayerHandle, WM_MIDI_PosUpdate, FCurrentTime, FCurrentPos) else PostMessage(FPlayerHandle, WM_MIDI_PosUpdate, FCurrentTime, FCurrentPos); if tmpSuspend then Suspend := false; end; Dann bitte eine/die Datei hochladen wo das Problem auftritt. Wenn die Problem durch die Änderung behoben sein sollten lade ich ein neues Archiv hoch. gruss Geändert von EWeiss ( 1. Jun 2015 um 05:14 Uhr) |
Zitat |
Delphi 10.1 Berlin Professional |
#84
Hallo,
gestern war bei uns Feiertag und darum blieb mal etwas Zeit für den MidiPlayer. Neue Erkenntniss: Das von mir geschilderte Problem hat nicht nur mit den SysEx zu tun - das habe ich jetzt übrigens durch Priority=HIGHEST verbessern können - sondern mit langen Noten. Besonders wenn sie sich überschneiden, was bei Flächensounds (Streicher, Orgel...) schon mal vorkommt, scheint es so zu sein, dass die Note-Off's nicht am Soundmodul ankommen. Ein Indiz dafür ist unter Anderem: Wenn ein Flächensound durch z.B. ein Piano ersetzt wird, dann ist das Phänomen weg. Weil das Problem nur schwer mit dem Debugger lösbar ist, bräuchte man jetzt mal ein Tool, das die im Midifile vorhandenen Events und die am Expander tatsächlich ankommenden Events vergleicht. Dann wäre es auch eine gesicherte Aussage. Den Quellcode habe ich mir zwar angesehen, aber da steige ich momentan noch nicht bzw. zu wenig durch. Alternative: Vielleicht hat Silhwan Hyun ja eine Idee? Wie schon gesagt, wenn es funktioniert bezahle ich auch gerne dafür. |
Zitat |
EWeiss
|
#85
Zitat:
Alternative: Vielleicht hat Silhwan Hyun ja eine Idee?
Kein Problem..
Zitat:
Wie schon gesagt, wenn es funktioniert bezahle ich auch gerne dafür.
Zitat:
Ich ändere etwas dran wenn ich zeit finde oder Lust dazu habe das soll nicht in MÜSSEN ausarten.
Bisher wurde auch kein Feedback bezüglich der Änderung im TMidiDriver.DoOnMidiTimer gegeben. Von dir die Aussagen sind etwas undurchsichtig (Ein Indiz).. Was haben unsere Änderungen bzgl. SysEx denn nun ergeben? gruss Geändert von EWeiss ( 5. Jun 2015 um 14:26 Uhr) |
Zitat |
Delphi 10.1 Berlin Professional |
#86
Zitat:
Alternative: Vielleicht hat Silhwan Hyun ja eine Idee?
Kein Problem.. Ich bin heute schon den ganzen Tag am Quellcode lesen und verstehen. Dabei bin ich auf ein paar Ungereimtheiten gestoßen die ich noch nicht zuordnen oder eindeutig beurteilen kann. Beispielsweise die Property Pitch in v0.9.4 vom 27 May 2012. FPitch wird nirgendwo initialisiert. Ist vielleicht auch nicht nötig, weil man davon ausgehen kann, dass es normalerweise "0" ist. Aber kann man auch sicher sein? Nachdem ich in den beiden constructoren mal "FPitch := 0" ergänzt habe, laufen wieder ein paar Midifiles mehr d.h. ein paar Notenhänger sind verschwunden. SysEx: Verlorene SysEx habe ich heute mit MidiOx keine mehr gefunden. Zumindest nicht auf meinem Entwickler-PC und meinem Test-PC. Wie schon gesagt, die Priority hat in der Hinsicht geholfen. Aber nicht auf meinem Auftritt-PC mit einem 1.6-er Atom. Der ist davon unbeeindruckt Es sind aber immer noch etwa 1/3 meiner Midi's die nicht laufen. Sorry, aber ich werde mich jetzt vorerst mal ausklinken weil die Freizeit derzeit eh sehr knapp ist. Die (Musik-)Saison hat begonnen und Brötchen verdienen muss ich auch noch so nebenbei |
Zitat |
EWeiss
|
#87
Bzgl. FPitch
Zitat:
Ray Lischners Delphi in a Nutshell Kapitel 2 (Seite 37)
Zitat:
When Delphi first creates an object, all of the fields start out empty,
that is, pointers are initialized to nil, strings and dynamic arrays are empty, numbers have the value zero, Boolean fields are False, and Variants are set to Unassigned. (See NewInstance and InitInstance in Chapter 5 for details.)
Zitat:
SysEx: Verlorene SysEx habe ich heute mit MidiOx keine mehr gefunden
An den Änderungen oder ausschließlich an der Priority. Ich behaupte einfach mal das es daran lag weil wir die SysExMsg (Events) nicht behandelt haben.
Zitat:
Es sind aber immer noch etwa 1/3 meiner Midi's die nicht laufen.
gruss Geändert von EWeiss ( 7. Jun 2015 um 15:06 Uhr) |
Zitat |
Delphi 10.1 Berlin Professional |
#88
Zitat:
SysEx: Verlorene SysEx habe ich heute mit MidiOx keine mehr gefunden
An den Änderungen oder ausschließlich an der Priority. Ich behaupte einfach mal das es daran lag weil wir die SysExMsg (Events) nicht behandelt haben. Hast du keinen MidiOx oder etwas Vergleichbares? Dann könntest du das auch kontrollieren bzw. nachvollziehen: Der MidiPlayer sendet bei einem im Midifile enthaltenen SysEx nur ein einziges Byte. Ein Bug den ich noch nicht gefunden habe, denn PutLong funktioniert prinzipiell. Mit der Erhöhung der Priorität wird wohl lediglich der SysEx etwas schneller verarbeitet (sprich die Routine kommt etwas schneller zurück) und dann passt das auch besser im Timing, denn in einem SysEx wird z.B. das KanalRouting geändert, was natürlich vor der ersten Note schon erledigt sein muss.
Zitat:
Zitat:
Es sind aber immer noch etwa 1/3 meiner Midi's die nicht laufen.
Hier öffentlich als Dateianlage geht nicht, weil meine Midi's natürlich ganz reell gekauft wurden und somit dem Copyright des Herstellers unterliegen. Ich müsste sie also z.B. nach 15 Sekunden abschneiden, dann wären sie für den normalen Einsatz unbrauchbar und mein Gewissen wäre beruhigt. |
Zitat |
EWeiss
|
#89
Zitat:
Es liegt daran, dass ich die SysEx-Verarbeitung im Driver einstellbar gemacht habe.
Mich interessiert es weniger ob du etwas geändert hast, sondern ob unsere Änderung im vergleich zu vorher irgendwelche Auswirkungen auf deine nicht funktionierenden Midi-Dateien hat. Wie schon gesagt haben wir die SysEx Events vorher nicht behandelt. Die Änderung! Nochmal zur Veranschaulichung.
Delphi-Quellcode:
if (not NoExclusiveMsg) then // for (pEvent^.Msg <> '')
if (EventCode = $F0) or (EventCode = $F7) then // $F7 - used as a Message continuation mark begin // if FChannelState[ChannelNo] then // MidiOut.PutLong(pAnsiChar(pEvent^.Msg), Length(pEvent^.Msg)); // * missed event code // * Bug fix : correction for missed event code (01 Jun 2015) SysExMsg := AnsiChar(EventCode) + pEvent^.Msg; MidiOut.PutLong(@SysExMsg[1], Length(SysExMsg)); end;
Zitat:
Danke für das Angebot! Ich hatte bisher nicht den Eindruck, dass sich darum dann jemand kümmert, und darum habe ich es sein lassen.
Aber verstehe bitte auch das so keine "Fehler?" behoben werden können. Ohne das wir einen Vergleich ziehen können. (Datei.. analysieren) gruss Geändert von EWeiss ( 8. Jun 2015 um 13:46 Uhr) |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |