diff options
Diffstat (limited to '')
-rw-r--r-- | src/screens/UScreenEditConvert.pas | 827 |
1 files changed, 0 insertions, 827 deletions
diff --git a/src/screens/UScreenEditConvert.pas b/src/screens/UScreenEditConvert.pas deleted file mode 100644 index b2fb7773..00000000 --- a/src/screens/UScreenEditConvert.pas +++ /dev/null @@ -1,827 +0,0 @@ -{* UltraStar Deluxe - Karaoke Game - * - * UltraStar Deluxe is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - *} - -unit UScreenEditConvert; - -{* - * See - * MIDI Recommended Practice (RP-017): SMF Lyric Meta Event Definition - * http://www.midi.org/techspecs/rp17.php - * MIDI Recommended Practice (RP-026): SMF Language and Display Extensions - * http://www.midi.org/techspecs/rp26.php - * MIDI File Format - * http://www.sonicspot.com/guide/midifiles.html - * KMIDI File Format - * http://gnese.free.fr/Projects/KaraokeTime/Fichiers/karfaq.html - * http://journals.rpungin.fotki.com/karaoke/category/midi - * - * There are two widely spread karaoke formats: - * - KMIDI (.kar), an inofficial midi extension by Tune 1000 - * - Standard Midi files with lyric meta-tags (SMF with lyrics, .mid). - * - * KMIDI uses two tracks, the first just contains a header (mostly track 2) and - * the second the lyrics (track 3). It uses text meta tags for the lyrics. - * SMF uses just one track (normally track 1) and uses lyric meta tags for storage. - * - * Most files are in the KMIDI format. Some Midi files contain both lyric types. - *} - -interface - -{$IFDEF FPC} - {$MODE Delphi} -{$ENDIF} - -{$I switches.inc} - -uses - math, - UMenu, - SDL, - {$IFDEF UseMIDIPort} - MidiFile, - MidiOut, - {$ENDIF} - ULog, - USongs, - USong, - UMusic, - UThemes, - UPath; - -type - TMidiNote = record - Event: integer; - EventType: integer; - Channel: integer; - Start: real; - Len: real; - Data1: integer; - Data2: integer; - Str: UTF8String; // normally ASCII - end; - - TLyricType = (ltKMIDI, ltSMFLyric); - - TTrack = record - Note: array of TMidiNote; - Name: UTF8String; // normally ASCII - Status: set of (tsNotes, tsLyrics); //< track contains notes, lyrics or both - LyricType: set of TLyricType; - NoteType: (ntNone, ntAvail); - end; - - TNote = record - Start: integer; - Len: integer; - Tone: integer; - Lyric: UTF8String; - NewSentence: boolean; - end; - - TArrayTrack = array of TTrack; - - TScreenEditConvert = class(TMenu) - private - Tracks: TArrayTrack; // current track - ColR: array[0..100] of real; - ColG: array[0..100] of real; - ColB: array[0..100] of real; - Len: real; - SelTrack: integer; // index of selected track - fFileName: IPath; - - {$IFDEF UseMIDIPort} - MidiFile: TMidiFile; - MidiOut: TMidiOutput; - {$ENDIF} - - BPM: real; - Ticks: real; - Note: array of TNote; - - procedure AddLyric(Start: integer; LyricType: TLyricType; Text: UTF8String); - procedure Extract(out Song: TSong; out Lines: TLines); - - {$IFDEF UseMIDIPort} - procedure MidiFile1MidiEvent(event: PMidiEvent); - {$ENDIF} - - function CountSelectedTracks: integer; - - public - constructor Create; override; - procedure OnShow; override; - function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override; - function Draw: boolean; override; - procedure OnHide; override; - end; - -implementation - -uses - SysUtils, - TextGL, - gl, - UDrawTexture, - UFiles, - UGraphic, - UIni, - UMain, - UPathUtils, - USkins, - ULanguage, - UTextEncoding, - UUnicodeUtils; - -const - // MIDI/KAR lyrics are specified to be ASCII only. - // Assume backward compatible CP1252 encoding. - DEFAULT_ENCODING = encCP1252; - -const - MIDI_EVENTTYPE_NOTEOFF = $8; - MIDI_EVENTTYPE_NOTEON = $9; - MIDI_EVENTTYPE_META_SYSEX = $F; - - MIDI_EVENT_META = $FF; - MIDI_META_TEXT = $1; - MIDI_META_LYRICS = $5; - -function TScreenEditConvert.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; -{$IFDEF UseMIDIPort} -var - SResult: TSaveSongResult; - Playing: boolean; - MidiTrack: TMidiTrack; - Song: TSong; - Lines: TLines; -{$ENDIF} -begin - Result := true; - if (PressedDown) then - begin // Key Down - // check normal keys - case UCS4UpperCase(CharCode) of - Ord('Q'): - begin - Result := false; - Exit; - end; - end; - - // check special keys - case PressedKey of - SDLK_ESCAPE, - SDLK_BACKSPACE : - begin - {$IFDEF UseMIDIPort} - if (MidiFile <> nil) then - MidiFile.StopPlaying; - {$ENDIF} - AudioPlayback.PlaySound(SoundLib.Back); - FadeTo(@ScreenEdit); - end; - - SDLK_RETURN: - begin - if Interaction = 0 then - begin - AudioPlayback.PlaySound(SoundLib.Start); - ScreenOpen.Filename := GamePath.Append('file.mid'); - ScreenOpen.BackScreen := @ScreenEditConvert; - FadeTo(@ScreenOpen); - end - else if Interaction = 1 then - begin - {$IFDEF UseMIDIPort} - if (MidiFile <> nil) then - begin - MidiFile.OnMidiEvent := MidiFile1MidiEvent; - //MidiFile.GoToTime(MidiFile.GetTrackLength div 2); - MidiFile.StartPlaying; - end; - {$ENDIF} - end - else if Interaction = 2 then - begin - {$IFDEF UseMIDIPort} - if (MidiFile <> nil) then - begin - MidiFile.OnMidiEvent := nil; - MidiFile.StartPlaying; - end; - {$ENDIF} - end - else if Interaction = 3 then - begin - {$IFDEF UseMIDIPort} - if CountSelectedTracks > 0 then - begin - Extract(Song, Lines); - SResult := SaveSong(Song, Lines, fFileName.SetExtension('.txt'), - false); - FreeAndNil(Song); - if (SResult = ssrOK) then - ScreenPopupInfo.ShowPopup(Language.Translate('INFO_FILE_SAVED')) - else - ScreenPopupError.ShowPopup(Language.Translate('ERROR_SAVE_FILE_FAILED')); - end - else - begin - ScreenPopupError.ShowPopup(Language.Translate('EDITOR_ERROR_NO_TRACK_SELECTED')); - end; - {$ENDIF} - end; - - end; - - SDLK_SPACE: - begin - {$IFDEF UseMIDIPort} - if (MidiFile <> nil) then - begin - if (Tracks[SelTrack].NoteType = ntAvail) and - (Tracks[SelTrack].LyricType <> []) then - begin - if (Tracks[SelTrack].Status = []) then - Tracks[SelTrack].Status := [tsNotes] - else if (Tracks[SelTrack].Status = [tsNotes]) then - Tracks[SelTrack].Status := [tsLyrics] - else if (Tracks[SelTrack].Status = [tsLyrics]) then - Tracks[SelTrack].Status := [tsNotes, tsLyrics] - else if (Tracks[SelTrack].Status = [tsNotes, tsLyrics]) then - Tracks[SelTrack].Status := []; - end - else if (Tracks[SelTrack].NoteType = ntAvail) then - begin - if (Tracks[SelTrack].Status = []) then - Tracks[SelTrack].Status := [tsNotes] - else - Tracks[SelTrack].Status := []; - end - else if (Tracks[SelTrack].LyricType <> []) then - begin - if (Tracks[SelTrack].Status = []) then - Tracks[SelTrack].Status := [tsLyrics] - else - Tracks[SelTrack].Status := []; - end; - - Playing := (MidiFile.GetCurrentTime > 0); - MidiFile.StopPlaying(); - MidiTrack := MidiFile.GetTrack(SelTrack); - if tsNotes in Tracks[SelTrack].Status then - MidiTrack.OnMidiEvent := MidiFile1MidiEvent - else - MidiTrack.OnMidiEvent := nil; - if (Playing) then - MidiFile.ContinuePlaying(); - end; - {$ENDIF} - end; - - SDLK_RIGHT: - begin - InteractNext; - end; - - SDLK_LEFT: - begin - InteractPrev; - end; - - SDLK_DOWN: - begin - Inc(SelTrack); - if SelTrack > High(Tracks) then - SelTrack := 0; - end; - SDLK_UP: - begin - Dec(SelTrack); - if SelTrack < 0 then - SelTrack := High(Tracks); - end; - end; - end; -end; - -procedure TScreenEditConvert.AddLyric(Start: integer; LyricType: TLyricType; Text: UTF8String); -var - N: integer; -begin - // find corresponding note - N := 0; - while (N <= High(Note)) do - begin - if Note[N].Start = Start then - Break; - Inc(N); - end; - - // check if note was found - if (N > High(Note)) then - Exit; - - // set text - if (LyricType = ltKMIDI) then - begin - // end of paragraph - if Copy(Text, 1, 1) = '\' then - begin - Delete(Text, 1, 1); - end - // end of line - else if Copy(Text, 1, 1) = '/' then - begin - Delete(Text, 1, 1); - Note[N].NewSentence := true; - end; - end - else // SMFLyric - begin - // Line Feed -> end of paragraph - if Copy(Text, 1, 1) = #$0A then - begin - Delete(Text, 1, 1); - end - // Carriage Return -> end of line - else if Copy(Text, 1, 1) = #$0D then - begin - Delete(Text, 1, 1); - Note[N].NewSentence := true; - end; - end; - - // overwrite lyric or append - if Note[N].Lyric = '-' then - Note[N].Lyric := Text - else - Note[N].Lyric := Note[N].Lyric + Text; -end; - -procedure TScreenEditConvert.Extract(out Song: TSong; out Lines: TLines); - -var - T: integer; - C: integer; - N: integer; - Nu: integer; - NoteTemp: TNote; - Move: integer; - Max, Min: integer; - LyricType: TLyricType; - Text: UTF8String; -begin - // song info - Song := TSong.Create(); - Song.Clear(); - Song.Resolution := 4; - SetLength(Song.BPM, 1); - Song.BPM[0].BPM := BPM*4; - SetLength(Note, 0); - - // extract notes - for T := 0 to High(Tracks) do - begin - if tsNotes in Tracks[T].Status then - begin - for N := 0 to High(Tracks[T].Note) do - begin - if (Tracks[T].Note[N].EventType = MIDI_EVENTTYPE_NOTEON) and - (Tracks[T].Note[N].Data2 > 0) then - begin - Nu := Length(Note); - SetLength(Note, Nu + 1); - Note[Nu].Start := Round(Tracks[T].Note[N].Start / Ticks); - Note[Nu].Len := Round(Tracks[T].Note[N].Len / Ticks); - Note[Nu].Tone := Tracks[T].Note[N].Data1 - 12*5; - Note[Nu].Lyric := '-'; - end; - end; - end; - end; - - // extract lyrics (and artist + title info) - for T := 0 to High(Tracks) do - begin - if not (tsLyrics in Tracks[T].Status) then - Continue; - - for N := 0 to High(Tracks[T].Note) do - begin - if (Tracks[T].Note[N].Event = MIDI_EVENT_META) then - begin - // determine and validate lyric meta tag - if (ltKMIDI in Tracks[T].LyricType) and - (Tracks[T].Note[N].Data1 = MIDI_META_TEXT) then - begin - Text := Tracks[T].Note[N].Str; - - // check for meta info - if (Length(Text) > 2) and (Text[1] = '@') then - begin - case Text[2] of - 'L': Song.Language := Copy(Text, 3, Length(Text)); // language - 'T': begin // title info - if (Song.Artist = '') then - Song.Artist := Copy(Text, 3, Length(Text)) - else if (Song.Title = '') then - Song.Title := Copy(Text, 3, Length(Text)); - end; - end; - Continue; - end; - - LyricType := ltKMIDI; - end - else if (ltSMFLyric in Tracks[T].LyricType) and - (Tracks[T].Note[N].Data1 = MIDI_META_LYRICS) then - begin - LyricType := ltSMFLyric; - end - else - begin - // unknown meta event - Continue; - end; - - AddLyric(Round(Tracks[T].Note[N].Start / Ticks), LyricType, Tracks[T].Note[N].Str); - end; - end; - end; - - // sort notes - for N := 0 to High(Note) do - for Nu := 0 to High(Note)-1 do - if Note[Nu].Start > Note[Nu+1].Start then - begin - NoteTemp := Note[Nu]; - Note[Nu] := Note[Nu+1]; - Note[Nu+1] := NoteTemp; - end; - - // move to 0 at beginning - Move := Note[0].Start; - for N := 0 to High(Note) do - Note[N].Start := Note[N].Start - Move; - - // copy notes - SetLength(Lines.Line, 1); - Lines.Number := 1; - Lines.High := 0; - Lines.Current := 0; - Lines.Resolution := 0; - Lines.NotesGAP := 0; - Lines.ScoreValue := 0; - - C := 0; - N := 0; - Lines.Line[C].HighNote := -1; - - for Nu := 0 to High(Note) do - begin - if Note[Nu].NewSentence then // new line - begin - SetLength(Lines.Line, Length(Lines.Line)+1); - Lines.Number := Lines.Number + 1; - Lines.High := Lines.High + 1; - C := C + 1; - N := 0; - SetLength(Lines.Line[C].Note, 0); - Lines.Line[C].HighNote := -1; - - //Calculate Start of the Last Sentence - if (C > 0) and (Nu > 0) then - begin - Max := Note[Nu].Start; - Min := Note[Nu-1].Start + Note[Nu-1].Len; - - case (Max - Min) of - 0: Lines.Line[C].Start := Max; - 1: Lines.Line[C].Start := Max; - 2: Lines.Line[C].Start := Max - 1; - 3: Lines.Line[C].Start := Max - 2; - else - if ((Max - Min) > 4) then - Lines.Line[C].Start := Min + 2 - else - Lines.Line[C].Start := Max; - - end; // case - - end; - end; - - // create space for new note - SetLength(Lines.Line[C].Note, Length(Lines.Line[C].Note)+1); - Inc(Lines.Line[C].HighNote); - - // initialize note - Lines.Line[C].Note[N].Start := Note[Nu].Start; - Lines.Line[C].Note[N].Length := Note[Nu].Len; - Lines.Line[C].Note[N].Tone := Note[Nu].Tone; - Lines.Line[C].Note[N].Text := DecodeStringUTF8(Note[Nu].Lyric, DEFAULT_ENCODING); - Lines.Line[C].Note[N].NoteType := ntNormal; - Inc(N); - end; -end; - -function TScreenEditConvert.CountSelectedTracks: integer; -var - T: integer; // track -begin - Result := 0; - for T := 0 to High(Tracks) do - if tsNotes in Tracks[T].Status then - Inc(Result); -end; - -{$IFDEF UseMIDIPort} -procedure TScreenEditConvert.MidiFile1MidiEvent(event: PMidiEvent); -begin - //Log.LogStatus(IntToStr(event.event), 'MIDI'); - try - MidiOut.PutShort(event.event, event.data1, event.data2); - except - MidiFile.StopPlaying(); - end; -end; -{$ENDIF} - -constructor TScreenEditConvert.Create; -var - P: integer; -begin - inherited Create; - AddButton(40, 20, 100, 40, Skin.GetTextureFileName('ButtonF')); - AddButtonText(15, 5, 0, 0, 0, 'Open'); - //Button[High(Button)].Text[0].Size := 11; - - AddButton(160, 20, 100, 40, Skin.GetTextureFileName('ButtonF')); - AddButtonText(25, 5, 0, 0, 0, 'Play'); - - AddButton(280, 20, 200, 40, Skin.GetTextureFileName('ButtonF')); - AddButtonText(25, 5, 0, 0, 0, 'Play Selected'); - - AddButton(500, 20, 100, 40, Skin.GetTextureFileName('ButtonF')); - AddButtonText(20, 5, 0, 0, 0, 'Save'); - - fFileName := PATH_NONE; - - for P := 0 to 100 do - begin - ColR[P] := Random(10)/10; - ColG[P] := Random(10)/10; - ColB[P] := Random(10)/10; - end; - -end; - -procedure TScreenEditConvert.OnShow; -var - T: integer; // track - N: integer; // note - {$IFDEF UseMIDIPort} - MidiTrack: TMidiTrack; - MidiEvent: PMidiEvent; - {$ENDIF} - FileOpened: boolean; - KMIDITrackIndex, SMFTrackIndex: integer; -begin - inherited; - - Interaction := 0; - -{$IFDEF UseMIDIPort} - MidiOut := TMidiOutput.Create(nil); - Log.LogInfo(MidiOut.ProductName, 'MIDI'); - MidiOut.Open; - MidiFile := nil; - SetLength(Tracks, 0); - - // Filename is only <> PATH_NONE if we called the OpenScreen before - fFilename := ScreenOpen.Filename; - if (fFilename = PATH_NONE) then - Exit; - ScreenOpen.Filename := PATH_NONE; - - FileOpened := false; - if fFileName.Exists then - begin - MidiFile := TMidiFile.Create(nil); - MidiFile.Filename := fFileName; - try - MidiFile.ReadFile; - FileOpened := true; - except - MidiFile.Free; - end; - end; - - if (not FileOpened) then - begin - ScreenPopupError.ShowPopup(Language.Translate('ERROR_FILE_NOT_FOUND')); - Exit; - end; - - Len := 0; - SelTrack := 0; - BPM := MidiFile.Bpm; - Ticks := MidiFile.TicksPerQuarter / 4; - - KMIDITrackIndex := -1; - SMFTrackIndex := -1; - - SetLength(Tracks, MidiFile.NumberOfTracks); - for T := 0 to MidiFile.NumberOfTracks-1 do - Tracks[T].LyricType := []; - - for T := 0 to MidiFile.NumberOfTracks-1 do - begin - MidiTrack := MidiFile.GetTrack(T); - MidiTrack.OnMidiEvent := nil; - Tracks[T].Name := DecodeStringUTF8(MidiTrack.getName, DEFAULT_ENCODING); - Tracks[T].NoteType := ntNone; - Tracks[T].Status := []; - - SetLength(Tracks[T].Note, MidiTrack.getEventCount()); - for N := 0 to MidiTrack.getEventCount-1 do - begin - MidiEvent := MidiTrack.GetEvent(N); - - Tracks[T].Note[N].Start := MidiEvent.time; - Tracks[T].Note[N].Len := MidiEvent.len; - Tracks[T].Note[N].Event := MidiEvent.event; - Tracks[T].Note[N].EventType := MidiEvent.event shr 4; - Tracks[T].Note[N].Channel := MidiEvent.event and $0F; - Tracks[T].Note[N].Data1 := MidiEvent.data1; - Tracks[T].Note[N].Data2 := MidiEvent.data2; - Tracks[T].Note[N].Str := DecodeStringUTF8(MidiEvent.str, DEFAULT_ENCODING); - - if (Tracks[T].Note[N].Event = MIDI_EVENT_META) then - begin - case (Tracks[T].Note[N].Data1) of - MIDI_META_TEXT: begin - // KMIDI lyrics (uses MIDI_META_TEXT events) - if (StrLComp(PAnsiChar(Tracks[T].Note[N].Str), '@KMIDI KARAOKE FILE', 19) = 0) and - (High(Tracks) >= T+1) then - begin - // The '@KMIDI ...' mark is in the first track (mostly named 'Soft Karaoke') - // but the lyrics are in the second track (named 'Words') - Tracks[T+1].LyricType := Tracks[T+1].LyricType + [ltKMIDI]; - KMIDITrackIndex := T+1; - end; - end; - MIDI_META_LYRICS: begin - // lyrics in Standard Midi File format found (uses MIDI_META_LYRICS events) - Tracks[T].LyricType := Tracks[T].LyricType + [ltSMFLyric]; - SMFTrackIndex := T; - end; - end; - end - else if (Tracks[T].Note[N].EventType = MIDI_EVENTTYPE_NOTEON) then - begin - // notes available - Tracks[T].NoteType := ntAvail; - end; - - if Tracks[T].Note[N].Start + Tracks[T].Note[N].Len > Len then - Len := Tracks[T].Note[N].Start + Tracks[T].Note[N].Len; - end; - end; - - // set default lyric track. Prefer KMIDI. - if (KMIDITrackIndex > -1) then - Tracks[KMIDITrackIndex].Status := Tracks[KMIDITrackIndex].Status + [tsLyrics] - else if (SMFTrackIndex > -1) then - Tracks[SMFTrackIndex].Status := Tracks[SMFTrackIndex].Status + [tsLyrics]; -{$ENDIF} -end; - -function TScreenEditConvert.Draw: boolean; -var - Count: integer; - Count2: integer; - Bottom: real; - X: real; - Y: real; - Height: real; - YSkip: real; - TrackName: UTF8String; -begin - // draw static menu - inherited Draw; - - Y := 100; - - Height := min(480, 40 * Length(Tracks)); - Bottom := Y + Height; - - YSkip := Height / Length(Tracks); - - // highlight selected track - DrawQuad(10, Y+SelTrack*YSkip, 780, YSkip, 0.8, 0.8, 0.8); - - // track-selection info - for Count := 0 to High(Tracks) do - if Tracks[Count].Status <> [] then - DrawQuad(10, Y + Count*YSkip, 50, YSkip, 0.8, 0.3, 0.3); - glColor3f(0, 0, 0); - for Count := 0 to High(Tracks) do - begin - if Tracks[Count].NoteType = ntAvail then - begin - if tsNotes in Tracks[Count].Status then - glColor3f(0, 0, 0) - else - glColor3f(0.7, 0.7, 0.7); - SetFontPos(25, Y + Count*YSkip + 10); - SetFontSize(15); - glPrint('N'); - end; - if Tracks[Count].LyricType <> [] then - begin - if tsLyrics in Tracks[Count].Status then - glColor3f(0, 0, 0) - else - glColor3f(0.7, 0.7, 0.7); - SetFontPos(40, Y + Count*YSkip + 10); - SetFontSize(15); - glPrint('L'); - end; - end; - - DrawLine( 10, Y, 10, Bottom, 0, 0, 0); - DrawLine( 60, Y, 60, Bottom, 0, 0, 0); - DrawLine(790, Y, 790, Bottom, 0, 0, 0); - - for Count := 0 to Length(Tracks) do - DrawLine(10, Y + Count*YSkip, 790, Y + Count*YSkip, 0, 0, 0); - - for Count := 0 to High(Tracks) do - begin - SetFontPos(65, Y + Count*YSkip); - SetFontSize(15); - glPrint(Tracks[Count].Name); - end; - - for Count := 0 to High(Tracks) do - begin - for Count2 := 0 to High(Tracks[Count].Note) do - begin - if Tracks[Count].Note[Count2].EventType = MIDI_EVENTTYPE_NOTEON then - DrawQuad(60 + Tracks[Count].Note[Count2].Start/Len * 725, - Y + (Count+1)*YSkip - Tracks[Count].Note[Count2].Data1*35/127, - 3, 3, - ColR[Count], ColG[Count], ColB[Count]); - if Tracks[Count].Note[Count2].EventType = 15 then - DrawLine(60 + Tracks[Count].Note[Count2].Start/Len * 725, Y + 0.75 * YSkip + Count*YSkip, - 60 + Tracks[Count].Note[Count2].Start/Len * 725, Y + YSkip + Count*YSkip, - ColR[Count], ColG[Count], ColB[Count]); - end; - end; - - // playing line - {$IFDEF UseMIDIPort} - if (MidiFile <> nil) then - X := 60 + MidiFile.GetCurrentTime/MidiFile.GetTrackLength*730; - {$ENDIF} - DrawLine(X, Y, X, Bottom, 0.3, 0.3, 0.3); - - Result := true; -end; - -procedure TScreenEditConvert.OnHide; -begin -{$IFDEF UseMIDIPort} - FreeAndNil(MidiFile); - MidiOut.Close; - FreeAndNil(MidiOut); -{$ENDIF} -end; - -end. |