@@ -131,7 +131,7 @@ begin |
| 131 |
$C: begin |
131 |
$C: begin |
| 132 |
if Params <> 0 then begin |
132 |
if Params <> 0 then begin |
| 133 |
OutCode := $C; |
133 |
OutCode := $C; |
| 134 |
OutParams.Value := Trunc((Params / $40)*$F); |
134 |
OutParams.Value := Round((Params / $40)*$F); |
| 135 |
end else begin |
135 |
end else begin |
| 136 |
OutCode := $E; |
136 |
OutCode := $E; |
| 137 |
OutParams.Value := 0; |
137 |
OutParams.Value := 0; |
@@ -159,6 +159,64 @@ begin |
| 159 |
ConvertEffect(MC.Effect.Code, MC.Effect.Params, Result.EffectCode, Result.EffectParams); |
159 |
ConvertEffect(MC.Effect.Code, MC.Effect.Params, Result.EffectCode, Result.EffectParams); |
| 160 |
end; |
160 |
end; |
| 161 |
|
161 |
|
|
|
162 |
function ConvertCellCh4(MR: TMODRow): TCell; |
|
|
163 |
var |
|
|
164 |
Instrument: Byte; |
|
|
165 |
NoiseBreak: Byte; |
|
|
166 |
Noise: Byte; |
|
|
167 |
|
|
|
168 |
PolyCounter: TPolynomialCounterRegister; |
|
|
169 |
Ch4Freq: Integer; |
|
|
170 |
RealR: Double; |
|
|
171 |
|
|
|
172 |
NoteIndex: Integer; |
|
|
173 |
begin |
|
|
174 |
// https://github.com/RichardULZ/gb-studio/blob/bf6d60ee2530791cae009e3a8cb6b28f900f08d7/buildTools/win32-ia32/mod2gbt/mod2gbt.c#L827 |
|
|
175 |
|
|
|
176 |
// This makes a smooth Ramp of every noise type, inspired by Pigu-A's Cherry Blossom Dive |
|
|
177 |
// SSSS WDDD, preserve Width bit, combine Shift + Divisor (ignore bit 0100), add pitch. |
|
|
178 |
// Divisor 4,5,6,7 can make any noise found in 0,1,2,3 unless with 0 Clock Shift. |
|
|
179 |
// Solution, add 4, add note, if less than 4, set bit 0x04 to 0, and remove 4 again. |
|
|
180 |
// Notes will pitch correctly using C D# F# A# C, scale has been divided by 3. |
|
|
181 |
|
|
|
182 |
if PeriodToCodeMap.TryGetData(MR.Note, NoteIndex) then begin |
|
|
183 |
Noise := 0; |
|
|
184 |
NoiseBreak := 0; |
|
|
185 |
|
|
|
186 |
if (MR.Instrument < 16) then |
|
|
187 |
writeln(StdErr, '[DEBUG] Note value ', MR.Note, ' was accompanied by incorrect instrument ', MR.Instrument); |
|
|
188 |
|
|
|
189 |
if (MR.Instrument < 32) and (MR.Instrument > 16) then begin |
|
|
190 |
Instrument := GBT_NOISE[((MR.Instrument - 16) and $1F)]; // Only 0 - 0xF implemented |
|
|
191 |
|
|
|
192 |
NoiseBreak := ((Instrument and $03) or (((Instrument and $F0) shr 2) + 4)); |
|
|
193 |
NoiseBreak := NoiseBreak - (Trunc((NoteIndex + 1) / 3) - 8); |
|
|
194 |
Noise := ((NoiseBreak and $03) or |
|
|
195 |
((IfThen((NoiseBreak - 4) < 0, $0, (NoiseBreak - 4)) and $3C) shl 2) or |
|
|
196 |
IfThen(NoiseBreak > 3, $04, $0)) or (Instrument and $08); |
|
|
197 |
|
|
|
198 |
PolyCounter.ByteValue := Noise; |
|
|
199 |
|
|
|
200 |
if PolyCounter.DividingRatio = 0 then |
|
|
201 |
RealR := 0.5 |
|
|
202 |
else |
|
|
203 |
RealR := PolyCounter.DividingRatio; |
|
|
204 |
|
|
|
205 |
Ch4Freq := Trunc((524288 / RealR) / 2**(PolyCounter.ShiftClockFrequency+1)); |
|
|
206 |
if not Ch4FreqToNoteCodeMap.TryGetData(Ch4Freq, Result.Note) then |
|
|
207 |
writeln(StdErr, '[DEBUG] Note value ', Result.Note, ' not found.'); |
|
|
208 |
end else |
|
|
209 |
Result.Note := NO_NOTE; |
|
|
210 |
end else |
|
|
211 |
Result.Note := NO_NOTE; |
|
|
212 |
|
|
|
213 |
if MR.Instrument <> 0 then |
|
|
214 |
Result.Instrument := 1 |
|
|
215 |
else |
|
|
216 |
Result.Instrument := 0; |
|
|
217 |
ConvertEffect(MR.Effect.Code, MR.Effect.Params, Result.EffectCode, Result.EffectParams); |
|
|
218 |
end; |
|
|
219 |
|
| 162 |
procedure TranscribeColumn(MP: TMODPattern; Pat: PPattern; Column: Integer); |
220 |
procedure TranscribeColumn(MP: TMODPattern; Pat: PPattern; Column: Integer); |
| 163 |
var |
221 |
var |
| 164 |
I: Integer; |
222 |
I: Integer; |
@@ -169,7 +227,10 @@ begin |
| 169 |
LastPlayedInstrument := 0; |
227 |
LastPlayedInstrument := 0; |
| 170 |
|
228 |
|
| 171 |
for I := Low(MP) to High(MP) do begin |
229 |
for I := Low(MP) to High(MP) do begin |
| 172 |
Pat^[I] := ConvertCell(MP[I, Column]); |
230 |
if Column = 4 then |
|
|
231 |
Pat^[I] := ConvertCellCh4(MP[I, Column]) |
|
|
232 |
else |
|
|
233 |
Pat^[I] := ConvertCell(MP[I, Column]); |
| 173 |
|
234 |
|
| 174 |
if (Pat^[I].EffectCode = $C) then begin |
235 |
if (Pat^[I].EffectCode = $C) then begin |
| 175 |
if (Pat^[I].Instrument = 0) then |
236 |
if (Pat^[I].Instrument = 0) then |
@@ -184,41 +245,6 @@ begin |
| 184 |
end; |
245 |
end; |
| 185 |
end; |
246 |
end; |
| 186 |
|
247 |
|
| 187 |
// https://github.com/RichardULZ/gb-studio/blob/master/buildTools/win32-ia32/mod2gbt/mod2gbt.c#L827 |
|
|
| 188 |
|
|
|
| 189 |
procedure TranscribeColumnCh4(MP: TMODPattern; Pat: PPattern); |
|
|
| 190 |
var |
|
|
| 191 |
MR: TMODRow; |
|
|
| 192 |
Instrument: Byte; |
|
|
| 193 |
NoiseBreak: Byte; |
|
|
| 194 |
Noise: Byte; |
|
|
| 195 |
begin |
|
|
| 196 |
MR := MP[I, 4]; |
|
|
| 197 |
Instrument = GBT_NOISE[((MR.Instrument - 16) and $1F)]; // Only 0 - 0xF implemented |
|
|
| 198 |
|
|
|
| 199 |
// Rulz writes: |
|
|
| 200 |
// This makes a smooth Ramp of every noise type, inspired by Pigu-A's Cherry Blossom Dive |
|
|
| 201 |
// SSSS WDDD, preserve Width bit, combine Shift + Divisor (ignore bit 0100), add pitch. |
|
|
| 202 |
// Divisor 4,5,6,7 can make any noise found in 0,1,2,3 unless with 0 Clock Shift. |
|
|
| 203 |
// Solution, add 4, add note, if less than 4, set bit 0x04 to 0, and remove 4 again. |
|
|
| 204 |
// Notes will pitch correctly using C D# F# A# C, scale has been divided by 3. |
|
|
| 205 |
if (MR.Instrument < 32) and (MR.Instrument > 16) then begin |
|
|
| 206 |
NoiseBreak := ((Instrument and $03) or (((Instrument and $F0) shr 2) + 4)); |
|
|
| 207 |
NoiseBreak := NoiseBreak - (((MR.Note + 1) / 3) - 8); |
|
|
| 208 |
Noise := ((NoiseBreak and $03) or |
|
|
| 209 |
((((NoiseBreak - 4) < 0 ? $0 : (NoiseBreak - 4)) and $3C) shl 2) or |
|
|
| 210 |
(NoiseBreak > 3 ? $04 : $0) ) or (Instrument and $08); |
|
|
| 211 |
end; |
|
|
| 212 |
if (samplenum < 32 && samplenum > 16) // Noise |
|
|
| 213 |
{ |
|
|
| 214 |
noise_break = ( (instrument & 0x03) | (((instrument & 0xF0) >> 2) + 4) ); |
|
|
| 215 |
noise_break = noise_break - (((note_index + 1) / 3) - 8); |
|
|
| 216 |
noise = ( (noise_break & 0x03) | |
|
|
| 217 |
((((noise_break - 4) < 0 ? 0x0 : (noise_break - 4)) & 0x3C) << 2) | |
|
|
| 218 |
(noise_break > 3 ? 0x04 : 0x0) ) | (instrument & 0x08); |
|
|
| 219 |
} |
|
|
| 220 |
end; |
|
|
| 221 |
|
|
|
| 222 |
function LoadSongFromModStream(Stream: TStream): TSong; |
248 |
function LoadSongFromModStream(Stream: TStream): TSong; |
| 223 |
var |
249 |
var |
| 224 |
ModFile: TMODFile; |
250 |
ModFile: TMODFile; |
@@ -275,7 +301,7 @@ begin |
| 275 |
TranscribeColumn(ModFile.Patterns[I], Result.Patterns.GetOrCreateNew(I*10 + 0), 1); |
301 |
TranscribeColumn(ModFile.Patterns[I], Result.Patterns.GetOrCreateNew(I*10 + 0), 1); |
| 276 |
TranscribeColumn(ModFile.Patterns[I], Result.Patterns.GetOrCreateNew(I*10 + 1), 2); |
302 |
TranscribeColumn(ModFile.Patterns[I], Result.Patterns.GetOrCreateNew(I*10 + 1), 2); |
| 277 |
TranscribeColumn(ModFile.Patterns[I], Result.Patterns.GetOrCreateNew(I*10 + 2), 3); |
303 |
TranscribeColumn(ModFile.Patterns[I], Result.Patterns.GetOrCreateNew(I*10 + 2), 3); |
| 278 |
TranscribeColumnCh4(ModFile.Patterns[I], Result.Patterns.GetOrCreateNew(I*10 + 3)); |
304 |
TranscribeColumn(ModFile.Patterns[I], Result.Patterns.GetOrCreateNew(I*10 + 3), 4); |
| 279 |
end; |
305 |
end; |
| 280 |
|
306 |
|
| 281 |
// Import the order table. Uses a weird numbering scheme because hUGE has |
307 |
// Import the order table. Uses a weird numbering scheme because hUGE has |