Commit 21d8231

Nick Faro committed on
Add ability to paste from FamiTracker
commit 21d8231ddfafde119083171cce4fea3819c9f354 parent 49d21cf
1 changed files +161−9
Modifiedclipboardutils.pas +161−9
@@ -13,19 +13,169 @@ type
13 function GetPastedCells: TSelection; 13 function GetPastedCells: TSelection;
14 procedure CopyCells(Selection: TSelection); 14 procedure CopyCells(Selection: TSelection);
15 15
16 function GetFamitrackerPastedCells: TSelection;
17
16 implementation 18 implementation
17 19
18 function ParseCell(Cell: String): TSelectedCell; 20 const
21 // FamiTrackerTypes.h
22 FTM_EFFECTS: array[0..44] of Integer = (
23 $0, //EF_NONE = 0,
24 $F, //EF_SPEED, // Speed
25 $B, //EF_JUMP, // Jump
26 $D, //EF_SKIP, // Skip
27 $0, //EF_HALT, // Halt
28 $C, //EF_VOLUME, // Volume
29 $3, //EF_PORTAMENTO, // Porta on
30 $0, //EF_PORTAOFF, // Porta off // unused
31 $0, //EF_SWEEPUP, // Sweep up
32 $0, //EF_SWEEPDOWN, // Sweep down
33 $0, //EF_ARPEGGIO, // Arpeggio
34 $4, //EF_VIBRATO, // Vibrato
35 $0, //EF_TREMOLO, // Tremolo
36 $0, //EF_PITCH, // Pitch
37 $0, //EF_DELAY, // Note delay
38 $0, //EF_DAC, // DAC setting
39 $1, //EF_PORTA_UP, // Portamento up
40 $2, //EF_PORTA_DOWN, // Portamento down
41 $9, //EF_DUTY_CYCLE, // Duty cycle
42 $0, //EF_SAMPLE_OFFSET, // Sample offset
43 $0, //EF_SLIDE_UP, // Slide up
44 $0, //EF_SLIDE_DOWN, // Slide down
45 $A, //EF_VOLUME_SLIDE, // Volume slide
46 $E, //EF_NOTE_CUT, // Note cut
47 $0, //EF_RETRIGGER, // DPCM retrigger
48 $0, //EF_DELAYED_VOLUME, // // // Delayed channel volume
49 $0, //EF_FDS_MOD_DEPTH, // FDS modulation depth
50 $0, //EF_FDS_MOD_SPEED_HI, // FDS modulation speed hi
51 $0, //EF_FDS_MOD_SPEED_LO, // FDS modulation speed lo
52 $0, //EF_DPCM_PITCH, // DPCM Pitch
53 $0, //EF_SUNSOFT_ENV_TYPE, // Sunsoft envelope type
54 $0, //EF_SUNSOFT_ENV_HI, // Sunsoft envelope high
55 $0, //EF_SUNSOFT_ENV_LO, // Sunsoft envelope low
56 $0, //EF_SUNSOFT_NOISE, // // // 050B Sunsoft noise period
57 $0, //EF_VRC7_PORT, // // // 050B VRC7 custom patch port
58 $0, //EF_VRC7_WRITE, // // // 050B VRC7 custom patch write
59 $E, //EF_NOTE_RELEASE, // // // Delayed release
60 $0, //EF_GROOVE, // // // Groove
61 $0, //EF_TRANSPOSE, // // // Delayed transpose
62 $0, //EF_N163_WAVE_BUFFER, // // // N163 wave buffer
63 $0, //EF_FDS_VOLUME, // // // FDS volume envelope
64 $0, //EF_FDS_MOD_BIAS, // // // FDS auto-FM bias
65 $0, //EF_PHASE_RESET, // Reset waveform phase without retriggering note (VRC6-only so far)
66 $0, //EF_HARMONIC, // Multiply the note pitch by an integer
67 $0 //EF_COUNT
68 );
69
70 type
71 // PatternEditorTypes.h
72 {$PACKENUM 4} // https://www.freepascal.org/docs-html/ref/refsu4.html
73 TFTMColumn = (
74 COLUMN_NOTE = 0,
75 COLUMN_INSTRUMENT = 1,
76 COLUMN_VOLUME = 2,
77 COLUMN_EFF1 = 3,
78 COLUMN_EFF2 = 4,
79 COLUMN_EFF3 = 5,
80 COLUMN_EFF4 = 6
81 );
82 {$PACKENUM 1}
83
84 // PatternEditorTypes.h
85 TFTMClipInfo = packed record
86 Channels: Integer;
87 Rows: Integer;
88 StartColumn: TFTMColumn;
89 EndColumn: TFTMColumn;
90 OleInfo: record
91 ChanOffset: Integer;
92 RowOffset: Integer;
93 end;
94 end;
95
96 // PatternNote.h
97 TFTMChanNote = packed record
98 Note: Byte;
99 Octave: Byte;
100 Vol: Byte;
101 Instrument: Byte;
102 EffNumber: array[0..3] of Byte;
103 EffParam: array[0..3] of Byte;
104 end;
105
106 function GetFamitrackerPastedCells: TSelection;
107 function FTMNoteToCell(Note: TFTMChanNote): TCell;
108 begin
109 case Note.Note of
110 0, 13, 14, 15: Result.Note := NO_NOTE;
111 else Result.Note := (C_3 + (Note.Note-1)) + (12*(Note.Octave - 1));
112 end;
113
114 if Note.Instrument = 64 then
115 Result.Instrument := 0
116 else
117 Result.Instrument := Note.Instrument;
19 118
20 function StrToInt_(S: String; out I: Integer; Hex: Boolean = False): Boolean; 119 if Note.Note in [13, 14, 15] then begin
120 Result.EffectCode := $E;
121 Result.EffectParams.Value := $00;
122 end else begin
123 Result.EffectCode := FTM_EFFECTS[Note.EffNumber[0]];
124 Result.EffectParams.Value := Note.EffParam[0];
125 end;
126 end;
127 function FTMColumnToPart(Col: TFTMColumn): TCellPart;
128 begin
129 case Col of
130 COLUMN_NOTE: Exit(cpNote);
131 COLUMN_INSTRUMENT: Exit(cpInstrument);
132 COLUMN_VOLUME: Exit(cpVolume);
133 COLUMN_EFF1..COLUMN_EFF4: Exit(cpEffectParams);
134 end;
135 end;
136 var
137 ClipInfo: TFTMClipInfo;
138 FTMNotes: packed array of TFTMChanNote;
139 S: TMemoryStream;
140 CH, I: Integer;
21 begin 141 begin
22 if Trim(S) = '' then Exit(False); 142 S := TMemoryStream.Create;
23 if Hex then S := 'x'+S; 143 try
24 if not TryStrToInt(S, I) then 144 Clipboard.GetFormat(Clipboard.FindFormatID('FamiTracker Pattern'), S);
25 I := 0; 145 S.Seek(0, soBeginning);
26 Result := True; 146
147 S.Read(ClipInfo, SizeOf(ClipInfo));
148 SetLength(FTMNotes, ClipInfo.Channels * ClipInfo.Rows);
149 S.Read(FTMNotes[0], SizeOf(TFTMChanNote) * ClipInfo.Channels * ClipInfo.Rows);
150
151 SetLength(Result, ClipInfo.Rows);
152
153 for I := 0 to ClipInfo.Rows-1 do begin
154 SetLength(Result[I], ClipInfo.Channels);
155 for CH := 0 to ClipInfo.Channels-1 do begin
156 Result[I, CH].Cell := FTMNoteToCell(FTMNotes[(CH * ClipInfo.Rows) + I]);
157 Result[I, CH].Parts := [cpNote, cpInstrument, cpVolume, cpEffectCode, cpEffectParams];
158 end;
159 end;
160
161 for I := 0 to ClipInfo.Rows-1 do begin
162 Result[I, 0].Parts *= [FTMColumnToPart(ClipInfo.StartColumn)..cpEffectParams];
163 Result[I, ClipInfo.Channels-1].Parts *= [cpNote..FTMColumnToPart(ClipInfo.EndColumn)];
164 end;
165 finally
166 S.Free;
167 end;
27 end; 168 end;
28 169
170 function ParseCell(Cell: String): TSelectedCell;
171 function StrToInt_(S: String; out I: Integer; Hex: Boolean = False): Boolean;
172 begin
173 if Trim(S) = '' then Exit(False);
174 if Hex then S := 'x'+S;
175 if not TryStrToInt(S, I) then
176 I := 0;
177 Result := True;
178 end;
29 var 179 var
30 Note, Instr, EffectCode, EffectParam: String; 180 Note, Instr, EffectCode, EffectParam: String;
31 Temp: Integer; 181 Temp: Integer;
@@ -34,8 +184,6 @@ begin
34 Instr := Cell.Substring(3, 2); 184 Instr := Cell.Substring(3, 2);
35 EffectCode := Cell.Substring(8, 1); 185 EffectCode := Cell.Substring(8, 1);
36 EffectParam := Cell.Substring(9, 2); 186 EffectParam := Cell.Substring(9, 2);
37 //EffectParam1 := Cell.Substring(9, 1);
38 //EffectParam2 := Cell.Substring(10, 1);
39 187
40 Result.Parts := [cpNote, cpInstrument, cpEffectCode, cpEffectParams]; 188 Result.Parts := [cpNote, cpInstrument, cpEffectCode, cpEffectParams];
41 189
@@ -60,7 +208,11 @@ var
60 Row: String; 208 Row: String;
61 I, J: Integer; 209 I, J: Integer;
62 begin 210 begin
211 if Clipboard.HasFormatName('FamiTracker Pattern') then
212 Exit(GetFamitrackerPastedCells);
213
63 SL := TStringList.Create; 214 SL := TStringList.Create;
215
64 try 216 try
65 try 217 try
66 SL.Text := Clipboard.AsText; 218 SL.Text := Clipboard.AsText;