1 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2 ▼ 簡易 MOD / XM プレイヤー(2001 / 03 / 08 版)
4 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
7 #define WARNING_LEVEL ( 2 )
9 #define TYPE_NOTAVAILABLE ( 0 )
10 #define TYPE_MOD ( 1 )
11 #define TYPE_S3M ( 2 )
16 #define SFT ( 12 ) /* 固定小数ビット数 */
18 #define ONE (1 << 12) /* 固定小数表記の 1 */
20 #define DECIMAL ((1 << 12) - 1) /* 固定小数の、少数部分抽出用 */
23 #define ENV_SUSTAIN ( 2 )
24 #define ENV_LOOP ( 4 )
26 #define SMP_LOOP ( 1 )
27 #define SMP_PINGPONGLOOP ( 2 )
28 #define SMP_16BIT ( 16 )
32 #define VM_16BIT ( 4 )
34 #define LINEAR_FREQUENCY ( 1 )
36 extern void LogMsg(void* instance,const char* format,...);
38 /* Vibrato Tremolo Panbrello Auto-Vibrato 共通波形データ */
39 static const S32 _aaWaveTable[7][64] =
43 0, 12, 25, 37, 49, 60, 71, 81, 90, 98, 106, 112, 117, 122, 125, 126
44 , 127, 126, 125, 122, 117, 112, 106, 98, 90, 81, 71, 60, 49, 37, 25, 12
45 , 0, -12, -25, -37, -49, -60, -71, -81, -90, -98,-106,-112,-117,-122,-125,-126
46 ,-127,-126,-125,-122,-117,-112,-106, -98, -90, -81, -71, -60, -49, -37, -25, -12
51 0, -12, -25, -37, -49, -60, -71, -81, -90, -98,-106,-112,-117,-122,-125,-126
52 ,-127,-126,-125,-122,-117,-112,-106, -98, -90, -81, -71, -60, -49, -37, -25, -12
53 , 0, 12, 25, 37, 49, 60, 71, 81, 90, 98, 106, 112, 117, 122, 125, 126
54 , 127, 126, 125, 122, 117, 112, 106, 98, 90, 81, 71, 60, 49, 37, 25, 12
59 0, -4, -8, -12, -16, -20, -24, -28, -32, -36, -40, -44, -48, -52, -56, -60
60 , -64, -68, -72, -76, -80, -84, -88, -92, -96,-100,-104,-108,-112,-116,-120,-124
61 , 127, 123, 119, 115, 111, 107, 103, 99, 95, 91, 87, 83, 79, 75, 71, 67
62 , 63, 59, 55, 51, 47, 43, 39, 35, 31, 27, 23, 19, 15, 11, 7, 3
67 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60
68 , 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124
69 ,-127,-123,-119,-115,-111,-107,-103, -99, -95, -91, -87, -83, -79, -75, -71, -67
70 , -63, -59, -55, -51, -47, -43, -39, -35, -31, -27, -23, -19, -15, -11, -7, -3
75 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127
76 , 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127
77 ,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127
78 ,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127
83 -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127
84 ,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127
85 , 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127
86 , 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127
91 98,-127, -43, 88, 102, 41, -65, -94, 125, 20, -71, -86, -70, -32, -16, -96
92 , 17, 72, 107, -5, 116, -69, -62, -40, 10, -61, 65, 109, -18, -38, -13, -76
93 , -23, 88, 21, -94, 8, 106, 21,-112, 6, 109, 20, -88, -30, 9,-127, 118
94 , 42, -34, 89, -4, -51, -72, 21, -29, 112, 123, 84,-101, -92, 98, -54, -95
98 /* Vibrato Tremolo Panbrello Auto-Vibrato 各種波形の割り当て */
99 static const S32 _aVibratoWaveType[4] = { 0 , 2 , 4 , 6 };
100 static const S32 _aTremoloWaveType[4] = { 0 , 2 , 4 , 6 };
101 static const S32 _aPanbrelloWaveType[4] = { 0 , 2 , 4 , 6 };
102 static const S32 _aAutoVibratoWaveType[5] = { 1 , 5 , 3 , 2 , 6 };
106 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
111 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
112 static S32 XM_PATTERN__Destruct(
113 XM_PATTERN *p /* this ポインター */
115 if( p == NULL ) return( FALSE );
117 if( p->pPatternData != NULL ){
118 FreeMemory( p->pPatternData );
119 p->pPatternData = NULL ;
127 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
128 ▼ XM_PATTERN 構造体の確保と初期化
132 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
133 static XM_PATTERN *XM_PATTERN__Create(
136 S32 size = sizeof( XM_PATTERN );
137 XM_PATTERN *p = reinterpret_cast<XM_PATTERN *>(AllocMemory( size ));
139 if( p == NULL ) return( NULL );
142 for( i=0 ; i<size ; i++ ) ((U8*)p)[i] = 0 ;
145 p->pPatternData = NULL ;
152 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
153 ▼ XM_INSTRUMENT 構造体の破棄
157 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
158 static S32 XM_INSTRUMENT__Destruct(
159 XM_INSTRUMENT *p /* this ポインター */
161 if( p == NULL ) return( FALSE );
169 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
170 ▼ XM_INSTRUMENT 構造体の確保と初期化
174 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
175 static XM_INSTRUMENT *XM_INSTRUMENT__Create(
178 S32 size = sizeof( XM_INSTRUMENT );
179 XM_INSTRUMENT *p = reinterpret_cast<XM_INSTRUMENT *>(AllocMemory( size ));
181 if( p == NULL ) return( NULL );
184 for( i=0 ; i<size ; i++ ) ((U8*)p)[i] = 0 ;
187 for( i=0 ; i<96 ; i++ ) p->apAllNoteXM_SAMPLE[ i ] = NULL ;
194 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
199 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
200 static S32 XM_SAMPLE__Destruct(
201 XM_SAMPLE *p /* this ポインター */
203 if( p == NULL ) return( FALSE );
205 if( p->pSampleData != NULL ){
206 FreeMemory( p->pSampleData );
207 p->pSampleData = NULL ;
215 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
216 ▼ XM_SAMPLE 構造体の確保と初期化
220 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
221 static XM_SAMPLE *XM_SAMPLE__Create(
224 S32 size = sizeof( XM_SAMPLE );
225 XM_SAMPLE *p = reinterpret_cast<XM_SAMPLE *>(AllocMemory( size ));
227 if( p == NULL ) return( NULL );
230 for( i=0 ; i<size ; i++ ) ((U8*)p)[i] = 0 ;
233 p->pSampleData = NULL ;
240 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
245 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
246 static S32 MOD__LoadSongAsXM(
251 U8 *pMusDat = (U8*)pMusDat_ ;
254 if( pMOD == NULL ) return( FALSE );
259 if( lMusDat - ofs < 60 ){
260 #if (WARNING_LEVEL >= 2)
261 LogMsg(pMOD->Instance,
262 "MOD__LoadSongAsXM : \n"
263 " データサイズが不足しています。XM_ID を読み込めません。\n"
267 MOD__ReleaseSong( pMOD );
272 memcpy( &pMOD->XmId.aszID_Text[0] , &pMusDat[ ofs + 0 ] , 17 );
273 memcpy( &pMOD->XmId.aszModuleName[0] , &pMusDat[ ofs + 17 ] , 20 );
274 pMOD->XmId.aszModuleName[20] = 0 ; /* 文字列終点 */
275 pMOD->XmId.ID_Byte = (S32)*((U8*) &pMusDat[ ofs + 37 ]);
276 memcpy( &pMOD->XmId.aszTrackerName[0] , &pMusDat[ ofs + 38 ] , 20 );
277 pMOD->XmId.aszTrackerName[20] = 0 ; /* 文字列終点 */
278 pMOD->XmId.VersionNumber = (S32)*((U16*)&pMusDat[ ofs + 58 ]);
282 if( memcmp( "Extended Module:" , &(pMOD->XmId.aszID_Text[0]) , 16 ) != 0
283 || pMOD->XmId.ID_Byte != 0x1a
285 #if (WARNING_LEVEL >= 2)
286 LogMsg(pMOD->Instance,
287 "MOD__LoadSongAsXM : \n"
288 " XM 形式識別文字列が存在しません。\n"
292 MOD__ReleaseSong( pMOD );
297 if( pMOD->XmId.VersionNumber < 0x103 ){
298 #if (WARNING_LEVEL >= 2)
299 LogMsg(pMOD->Instance,
300 "MOD__LoadSongAsXM : \n"
301 " フォーマットのバージョンが古すぎます。\n"
305 MOD__ReleaseSong( pMOD );
309 #if (WARNING_LEVEL >= 2)
310 LogMsg(pMOD->Instance,
311 "MOD__LoadSongAsXM : ModName = %s \n"
312 ,pMOD->XmId.aszModuleName
315 LogMsg(pMOD->Instance,
316 "MOD__LoadSongAsXM : TrackerName = %s \n"
317 ,pMOD->XmId.aszTrackerName
326 if( lMusDat - ofs < 276 ){
327 #if (WARNING_LEVEL >= 2)
328 LogMsg(pMOD->Instance,
329 "MOD__LoadSongAsXM : \n"
330 " データサイズが不足しています。XM_HEADER を読み込めません。\n"
334 MOD__ReleaseSong( pMOD );
339 pMOD->XmHeader.HeaderSize = (S32)*((S32*)&pMusDat[ ofs + 0 ]);
340 pMOD->XmHeader.SongLength = (S32)*((U16*)&pMusDat[ ofs + 4 ]);
341 pMOD->XmHeader.RestartPosition = (S32)*((U16*)&pMusDat[ ofs + 6 ]);
342 pMOD->XmHeader.NumberOfChannels = (S32)*((U16*)&pMusDat[ ofs + 8 ]);
343 pMOD->XmHeader.NumberOfPatterns = (S32)*((U16*)&pMusDat[ ofs + 10 ]);
344 pMOD->XmHeader.NumberOfInstruments = (S32)*((U16*)&pMusDat[ ofs + 12 ]);
345 pMOD->XmHeader.Flags = (S32)*((U16*)&pMusDat[ ofs + 14 ]);
346 pMOD->XmHeader.DefaultTempo = (S32)*((U16*)&pMusDat[ ofs + 16 ]);
347 pMOD->XmHeader.DefaultBPM = (S32)*((U16*)&pMusDat[ ofs + 18 ]);
348 memcpy( &(pMOD->XmHeader.aPatternOrderTable[0]) , &pMusDat[ ofs + 20 ] , 256 );
349 ofs += pMOD->XmHeader.HeaderSize ;
351 #if (WARNING_LEVEL >= 3)
352 LogMsg(pMOD->Instance,
353 "MOD__LoadSongAsXM : \n"
354 " pMOD->XmHeader.HeaderSize %d \n"
355 " pMOD->XmHeader.SongLength %d \n"
356 " pMOD->XmHeader.RestartPosition %d \n"
357 " pMOD->XmHeader.NumberOfChannels %d \n"
358 " pMOD->XmHeader.NumberOfPatterns %d \n"
359 " pMOD->XmHeader.NumberOfInstruments %d \n"
360 " pMOD->XmHeader.Flags %d \n"
361 " pMOD->XmHeader.DefaultTempo %d \n"
362 " pMOD->XmHeader.DefaultBPM %d \n"
363 ,pMOD->XmHeader.HeaderSize
364 ,pMOD->XmHeader.SongLength
365 ,pMOD->XmHeader.RestartPosition
366 ,pMOD->XmHeader.NumberOfChannels
367 ,pMOD->XmHeader.NumberOfPatterns
368 ,pMOD->XmHeader.NumberOfInstruments
369 ,pMOD->XmHeader.Flags
370 ,pMOD->XmHeader.DefaultTempo
371 ,pMOD->XmHeader.DefaultBPM
376 if( pMOD->XmHeader.SongLength > 256
377 || pMOD->XmHeader.SongLength == 0
378 || pMOD->XmHeader.NumberOfChannels > MAX_CHANNELS
379 || pMOD->XmHeader.NumberOfChannels == 0
380 || pMOD->XmHeader.NumberOfPatterns > MAX_PATTERNS
381 || pMOD->XmHeader.NumberOfPatterns == 0
382 || pMOD->XmHeader.NumberOfInstruments > MAX_INSTRUMENTS
383 || pMOD->XmHeader.NumberOfInstruments == 0
385 #if (WARNING_LEVEL >= 2)
386 LogMsg(pMOD->Instance,
387 "MOD__LoadSongAsXM : \n"
388 " XM_HEADER に無効な値が含まれています。\n"
392 MOD__ReleaseSong( pMOD );
398 /* XM_PATTERN の読み込み */
403 for( idxPattern = 0 ; idxPattern < pMOD->XmHeader.NumberOfPatterns ; idxPattern++ ){
405 XM_PATTERN *pXM_PATTERN = XM_PATTERN__Create( );
408 if( pXM_PATTERN == NULL ){
409 #if (WARNING_LEVEL >= 1)
410 LogMsg(pMOD->Instance,
411 "MOD__LoadSongAsXM : \n"
412 " XM_PATTERN 構造体の確保に失敗しました。\n"
416 MOD__ReleaseSong( pMOD );
420 pMOD->apXM_PATTERN[ idxPattern ] = pXM_PATTERN ;
423 if( lMusDat - ofs < 9 ){
424 #if (WARNING_LEVEL >= 2)
425 LogMsg(pMOD->Instance,
426 "MOD__LoadSongAsXM : \n"
427 " データサイズが不足しています。XM_PATTERN を読み込めません。\n"
431 MOD__ReleaseSong( pMOD );
436 pXM_PATTERN->PatternHeaderLength = (S32)*((S32*)&pMusDat[ ofs + 0 ]);
437 pXM_PATTERN->PackingType = (S32)*((U8*) &pMusDat[ ofs + 4 ]);
438 pXM_PATTERN->NumberOfRowsInPattern = (S32)*((U16*)&pMusDat[ ofs + 5 ]);
439 pXM_PATTERN->PackedPatterndataSize = (S32)*((U16*)&pMusDat[ ofs + 7 ]);
442 #if (WARNING_LEVEL >= 3)
443 LogMsg(pMOD->Instance,
444 "MOD__LoadSongAsXM : \n"
445 " pXM_PATTERN->PatternHeaderLength %d \n"
446 " pXM_PATTERN->PackingType %d \n"
447 " pXM_PATTERN->NumberOfRowsInPattern %d \n"
448 " pXM_PATTERN->PackedPatterndataSize %d \n"
449 ,pXM_PATTERN->PatternHeaderLength
450 ,pXM_PATTERN->PackingType
451 ,pXM_PATTERN->NumberOfRowsInPattern
452 ,pXM_PATTERN->PackedPatterndataSize
457 if( pXM_PATTERN->NumberOfRowsInPattern == 0 ){
458 #if (WARNING_LEVEL >= 2)
459 LogMsg(pMOD->Instance,
460 "MOD__LoadSongAsXM : \n"
461 " XM_PATTERN に無効な値が含まれています。\n"
465 MOD__ReleaseSong( pMOD );
470 Size = 5 * pXM_PATTERN->NumberOfRowsInPattern * pMOD->XmHeader.NumberOfChannels ;
471 pXM_PATTERN->pPatternData = reinterpret_cast<U8*>(AllocMemory( Size ));
474 if( pXM_PATTERN->pPatternData == NULL ){
475 #if (WARNING_LEVEL >= 1)
476 LogMsg(pMOD->Instance,
477 "MOD__LoadSongAsXM : \n"
478 " パターン展開先メモリの確保に失敗しました。\n"
482 MOD__ReleaseSong( pMOD );
487 for( i=0 ; i<Size ; i++ ) pXM_PATTERN->pPatternData[ i ] = 0 ;
490 if( lMusDat - ofs < pXM_PATTERN->PackedPatterndataSize ){
491 #if (WARNING_LEVEL >= 2)
492 LogMsg(pMOD->Instance,
493 "MOD__LoadSongAsXM : \n"
494 " データサイズが不足しています。圧縮パターンデータを読み込めません。\n"
498 MOD__ReleaseSong( pMOD );
502 if( pXM_PATTERN->PackedPatterndataSize ){
503 S32 PackLeft = pXM_PATTERN->PackedPatterndataSize ;
504 U8 *pUnPacked = pXM_PATTERN->pPatternData ;
505 U8 *pPacked = &pMusDat[ ofs ];
508 U8 Flag = *pPacked++ ;
515 *pUnPacked++ = *pPacked++ ;
522 *pUnPacked++ = *pPacked++ ;
529 *pUnPacked++ = *pPacked++ ;
536 *pUnPacked++ = *pPacked++ ;
541 /* Effect parameter */
543 *pUnPacked++ = *pPacked++ ;
549 *pUnPacked++ = Flag ; /* Note */
550 *pUnPacked++ = *pPacked++ ; /* Instrument */
551 *pUnPacked++ = *pPacked++ ; /* Volume column */
552 *pUnPacked++ = *pPacked++ ; /* Effect */
553 *pUnPacked++ = *pPacked++ ; /* Effect parameter */
558 ofs += pXM_PATTERN->PackedPatterndataSize ;
563 /* XM_INSTRUMENT の読み込み */
567 for( idxInst = 0 ; idxInst < pMOD->XmHeader.NumberOfInstruments ; idxInst++ ){
568 XM_INSTRUMENT *pXM_INSTRUMENT = XM_INSTRUMENT__Create( );
571 if( pXM_INSTRUMENT == NULL ){
572 #if (WARNING_LEVEL >= 1)
573 LogMsg(pMOD->Instance,
574 "MOD__LoadSongAsXM : \n"
575 " XM_INSTRUMENT 構造体の確保に失敗しました。\n"
579 MOD__ReleaseSong( pMOD );
583 pMOD->apXM_INSTRUMENT[ idxInst ] = pXM_INSTRUMENT ;
586 if( lMusDat - ofs < 29 ){
587 #if (WARNING_LEVEL >= 2)
588 LogMsg(pMOD->Instance,
589 "MOD__LoadSongAsXM : \n"
590 " データサイズが不足しています。XM_INSTRUMENT(+28 まで)を読み込めません。\n"
594 MOD__ReleaseSong( pMOD );
599 pXM_INSTRUMENT->InstrumentSize = (S32)*((S32*)&pMusDat[ ofs + 0 ]);
600 memcpy( &pXM_INSTRUMENT->aszInstrumentName[0] , &pMusDat[ ofs + 4 ] , 22 );
601 pXM_INSTRUMENT->aszInstrumentName[22] = 0 ; /* 文字列終点 */
602 pXM_INSTRUMENT->InstrumentType = (S32)*((U8*) &pMusDat[ ofs + 26 ]);
603 pXM_INSTRUMENT->NumberOfSamplesInInstrument = (S32)*((U16*)&pMusDat[ ofs + 27 ]);
605 #if (WARNING_LEVEL >= 3)
606 LogMsg(pMOD->Instance,
607 "MOD__LoadSongAsXM : \n"
608 " pXM_INSTRUMENT->InstrumentSize %d \n"
609 " pXM_INSTRUMENT->aszInstrumentName %s \n"
610 " pXM_INSTRUMENT->InstrumentType %d \n"
611 " pXM_INSTRUMENT->NumberOfSamplesInInstrument %d \n"
612 ,pXM_INSTRUMENT->InstrumentSize
613 ,pXM_INSTRUMENT->aszInstrumentName
614 ,pXM_INSTRUMENT->InstrumentType
615 ,pXM_INSTRUMENT->NumberOfSamplesInInstrument
620 if( pXM_INSTRUMENT->NumberOfSamplesInInstrument > MAX_SAMPLES_IN_INSTRUMENT ){
621 #if (WARNING_LEVEL >= 2)
622 LogMsg(pMOD->Instance,
623 "MOD__LoadSongAsXM : \n"
625 " pXM_INSTRUMENT->NumberOfSamplesInInstrument = %d \n"
629 MOD__ReleaseSong( pMOD );
633 if( pXM_INSTRUMENT->NumberOfSamplesInInstrument == 0 ){
634 ofs += pXM_INSTRUMENT->InstrumentSize ;
638 if( lMusDat - ofs < 243 ){
639 #if (WARNING_LEVEL >= 2)
640 LogMsg(pMOD->Instance,
641 "MOD__LoadSongAsXM : \n"
642 " データサイズが不足しています。XM_INSTRUMENT(+29 以降)を読み込めません。\n"
646 MOD__ReleaseSong( pMOD );
651 pXM_INSTRUMENT->SampleHeaderSize = (S32)*((S32*)&pMusDat[ ofs + 29 ]);
652 memcpy( &pXM_INSTRUMENT->aSampleNumberForAllNotes[0] , &pMusDat[ ofs + 33 ] , 96 );
653 memcpy( &pXM_INSTRUMENT->aPointsForVolumeEnvelope[0] , &pMusDat[ ofs + 129 ] , 48 );
654 memcpy( &pXM_INSTRUMENT->aPointsForPanningEnvelope[0] , &pMusDat[ ofs + 177 ] , 48 );
655 pXM_INSTRUMENT->NumberOfVolumePoints = (S32)*((U8*) &pMusDat[ ofs + 225 ]);
656 pXM_INSTRUMENT->NumberOfPanningPoints = (S32)*((U8*) &pMusDat[ ofs + 226 ]);
657 pXM_INSTRUMENT->VolumeSustainPoint = (S32)*((U8*) &pMusDat[ ofs + 227 ]);
658 pXM_INSTRUMENT->VolumeLoopStartPoint = (S32)*((U8*) &pMusDat[ ofs + 228 ]);
659 pXM_INSTRUMENT->VolumeLoopEndPoint = (S32)*((U8*) &pMusDat[ ofs + 229 ]);
660 pXM_INSTRUMENT->PanningSustainPoint = (S32)*((U8*) &pMusDat[ ofs + 230 ]);
661 pXM_INSTRUMENT->PanningLoopStartPoint = (S32)*((U8*) &pMusDat[ ofs + 231 ]);
662 pXM_INSTRUMENT->PanningLoopEndPoint = (S32)*((U8*) &pMusDat[ ofs + 232 ]);
663 pXM_INSTRUMENT->VolumeType = (S32)*((U8*) &pMusDat[ ofs + 233 ]);
664 pXM_INSTRUMENT->PanningType = (S32)*((U8*) &pMusDat[ ofs + 234 ]);
665 pXM_INSTRUMENT->AutoVibratoType = (S32)*((U8*) &pMusDat[ ofs + 235 ]);
666 pXM_INSTRUMENT->AutoVibratoSweep = (S32)*((U8*) &pMusDat[ ofs + 236 ]);
667 pXM_INSTRUMENT->AutoVibratoDepth = (S32)*((U8*) &pMusDat[ ofs + 237 ]);
668 pXM_INSTRUMENT->AutoVibratoRate = (S32)*((U8*) &pMusDat[ ofs + 238 ]);
669 pXM_INSTRUMENT->VolumeFadeout = (S32)*((U16*)&pMusDat[ ofs + 239 ]);
670 pXM_INSTRUMENT->Reserved = (S32)*((U16*)&pMusDat[ ofs + 241 ]);
671 ofs += pXM_INSTRUMENT->InstrumentSize ;
673 #if (WARNING_LEVEL >= 3)
674 LogMsg(pMOD->Instance,
675 "MOD__LoadSongAsXM : \n"
676 " pXM_INSTRUMENT->SampleHeaderSize %d \n"
677 " pXM_INSTRUMENT->NumberOfVolumePoints %d \n"
678 " pXM_INSTRUMENT->NumberOfPanningPoints %d \n"
679 " pXM_INSTRUMENT->VolumeSustainPoint %d \n"
680 " pXM_INSTRUMENT->VolumeLoopStartPoint %d \n"
681 " pXM_INSTRUMENT->VolumeLoopEndPoint %d \n"
682 " pXM_INSTRUMENT->PanningSustainPoint %d \n"
683 " pXM_INSTRUMENT->PanningLoopStartPoint %d \n"
684 " pXM_INSTRUMENT->PanningLoopEndPoint %d \n"
685 " pXM_INSTRUMENT->VolumeType %d \n"
686 " pXM_INSTRUMENT->PanningType %d \n"
687 " pXM_INSTRUMENT->VibratoType %d \n"
688 " pXM_INSTRUMENT->VibratoSweep %d \n"
689 " pXM_INSTRUMENT->VibratoDepth %d \n"
690 " pXM_INSTRUMENT->VibratoRate %d \n"
691 " pXM_INSTRUMENT->VolumeFadeout %d \n"
692 " pXM_INSTRUMENT->Reserved %d \n"
693 ,pXM_INSTRUMENT->SampleHeaderSize
694 ,pXM_INSTRUMENT->NumberOfVolumePoints
695 ,pXM_INSTRUMENT->NumberOfPanningPoints
696 ,pXM_INSTRUMENT->VolumeSustainPoint
697 ,pXM_INSTRUMENT->VolumeLoopStartPoint
698 ,pXM_INSTRUMENT->VolumeLoopEndPoint
699 ,pXM_INSTRUMENT->PanningSustainPoint
700 ,pXM_INSTRUMENT->PanningLoopStartPoint
701 ,pXM_INSTRUMENT->PanningLoopEndPoint
702 ,pXM_INSTRUMENT->VolumeType
703 ,pXM_INSTRUMENT->PanningType
704 ,pXM_INSTRUMENT->AutoVibratoType
705 ,pXM_INSTRUMENT->AutoVibratoSweep
706 ,pXM_INSTRUMENT->AutoVibratoDepth
707 ,pXM_INSTRUMENT->AutoVibratoRate
708 ,pXM_INSTRUMENT->VolumeFadeout
709 ,pXM_INSTRUMENT->Reserved
713 /* 各キーに割り当てられたサンプリング番号を表示 */
716 LogMsg( pMOD->Instance," pXM_INSTRUMENT->aSampleNumberForAllNotes[] = { \n" );
717 for( i=0 ; i<96 ; i+=12 ){
718 LogMsg(pMOD->Instance, " " );
719 for( j=i ; j<i+12 ; j++ ){
720 LogMsg(pMOD->Instance,
722 ,pXM_INSTRUMENT->aSampleNumberForAllNotes[j]
725 LogMsg(pMOD->Instance, "\n" );
727 LogMsg( pMOD->Instance," } \n" );
734 if( pXM_INSTRUMENT->NumberOfVolumePoints > 12 ) pXM_INSTRUMENT->NumberOfVolumePoints = 12 ;
735 if( pXM_INSTRUMENT->NumberOfPanningPoints > 12 ) pXM_INSTRUMENT->NumberOfPanningPoints = 12 ;
736 if( pXM_INSTRUMENT->VolumeSustainPoint > 11 ) pXM_INSTRUMENT->VolumeSustainPoint = 11 ;
737 if( pXM_INSTRUMENT->VolumeLoopStartPoint > 11 ) pXM_INSTRUMENT->VolumeLoopStartPoint = 11 ;
738 if( pXM_INSTRUMENT->VolumeLoopEndPoint > 11 ) pXM_INSTRUMENT->VolumeLoopEndPoint = 11 ;
739 if( pXM_INSTRUMENT->PanningSustainPoint > 11 ) pXM_INSTRUMENT->PanningSustainPoint = 11 ;
740 if( pXM_INSTRUMENT->PanningLoopStartPoint > 11 ) pXM_INSTRUMENT->PanningLoopStartPoint = 11 ;
741 if( pXM_INSTRUMENT->PanningLoopEndPoint > 11 ) pXM_INSTRUMENT->PanningLoopEndPoint = 11 ;
743 /* エンベロープ変化を先に展開してテーブル化 */
747 if( pXM_INSTRUMENT->VolumeType & ENV_ON ){
748 for( idxPoint = 0 ; idxPoint <= 11 ; idxPoint++ ){
749 /* 逸脱して長いエンベロープデータを補正 */
750 if( pXM_INSTRUMENT->aPointsForVolumeEnvelope[ idxPoint ].x > 324 ){
751 pXM_INSTRUMENT->aPointsForVolumeEnvelope[ idxPoint ].x = 324 ;
754 if( pXM_INSTRUMENT->aPointsForVolumeEnvelope[ idxPoint ].y > 255 ){
755 pXM_INSTRUMENT->aPointsForVolumeEnvelope[ idxPoint ].y = 255 ;
759 for( idxPoint = 0 ; idxPoint < pXM_INSTRUMENT->NumberOfVolumePoints - 1 ; idxPoint++ ){
760 S32 x , y , dx , dy ;
762 x = pXM_INSTRUMENT->aPointsForVolumeEnvelope[ idxPoint ].x ;
763 y = pXM_INSTRUMENT->aPointsForVolumeEnvelope[ idxPoint ].y ;
764 dx = pXM_INSTRUMENT->aPointsForVolumeEnvelope[ idxPoint + 1 ].x - x ;
765 dy = pXM_INSTRUMENT->aPointsForVolumeEnvelope[ idxPoint + 1 ].y - y ;
769 for( x = 0 ; x < dx ; x++ ){
770 pXM_INSTRUMENT->VolumeEnvelopeTable[
771 x + pXM_INSTRUMENT->aPointsForVolumeEnvelope[ idxPoint ].x
772 ] = (U8)(y + dy * x / dx) ;
776 /* 終点に達したら、最終値をテーブル末端まで維持 */
777 if( idxPoint == pXM_INSTRUMENT->NumberOfVolumePoints - 2 ){
778 for( x = pXM_INSTRUMENT->aPointsForVolumeEnvelope[ idxPoint + 1 ].x ; x < 325 ; x++ ){
779 U16 Val = pXM_INSTRUMENT->aPointsForVolumeEnvelope[ idxPoint + 1 ].y ;
780 pXM_INSTRUMENT->VolumeEnvelopeTable[ x ] = (U8)Val ;
785 /* 制御点ナンバーから、テーブルオフセットに変換 */
786 pXM_INSTRUMENT->VolumeSustainPoint
787 = pXM_INSTRUMENT->aPointsForVolumeEnvelope[ pXM_INSTRUMENT->VolumeSustainPoint ].x ;
788 pXM_INSTRUMENT->VolumeLoopStartPoint
789 = pXM_INSTRUMENT->aPointsForVolumeEnvelope[ pXM_INSTRUMENT->VolumeLoopStartPoint ].x ;
790 pXM_INSTRUMENT->VolumeLoopEndPoint
791 = pXM_INSTRUMENT->aPointsForVolumeEnvelope[ pXM_INSTRUMENT->VolumeLoopEndPoint ].x ;
793 /* ループ区間の長さが 0 の時は、ループを無効化 */
794 if( pXM_INSTRUMENT->VolumeLoopStartPoint == pXM_INSTRUMENT->VolumeLoopEndPoint ){
795 pXM_INSTRUMENT->VolumeType &= ~ENV_LOOP ;
799 if( pXM_INSTRUMENT->PanningType & ENV_ON ){
800 for( idxPoint = 0 ; idxPoint <= 11 ; idxPoint++ ){
801 /* 逸脱して長いエンベロープデータを補正 */
802 if( pXM_INSTRUMENT->aPointsForPanningEnvelope[ idxPoint ].x > 324 ){
803 pXM_INSTRUMENT->aPointsForPanningEnvelope[ idxPoint ].x = 324 ;
806 if( pXM_INSTRUMENT->aPointsForVolumeEnvelope[ idxPoint ].y > 255 ){
807 pXM_INSTRUMENT->aPointsForVolumeEnvelope[ idxPoint ].y = 255 ;
811 for( idxPoint = 0 ; idxPoint < pXM_INSTRUMENT->NumberOfPanningPoints - 1 ; idxPoint++ ){
812 S32 x , y , dx , dy ;
814 x = pXM_INSTRUMENT->aPointsForPanningEnvelope[ idxPoint ].x ;
815 y = pXM_INSTRUMENT->aPointsForPanningEnvelope[ idxPoint ].y ;
816 dx = pXM_INSTRUMENT->aPointsForPanningEnvelope[ idxPoint + 1 ].x - x ;
817 dy = pXM_INSTRUMENT->aPointsForPanningEnvelope[ idxPoint + 1 ].y - y ;
821 for( x = 0 ; x < dx ; x++ ){
822 pXM_INSTRUMENT->PanningEnvelopeTable[
823 x + pXM_INSTRUMENT->aPointsForPanningEnvelope[ idxPoint ].x
824 ] = (U8)(y + dy * x / dx) ;
828 /* 終点に達したら、最終値をテーブル末端まで維持 */
829 if( idxPoint == pXM_INSTRUMENT->NumberOfPanningPoints - 2 ){
830 for( x = pXM_INSTRUMENT->aPointsForPanningEnvelope[ idxPoint + 1 ].x ; x < 325 ; x++ ){
831 U16 Val = pXM_INSTRUMENT->aPointsForPanningEnvelope[ idxPoint + 1 ].y ;
832 pXM_INSTRUMENT->PanningEnvelopeTable[ x ] = (U8)Val ;
837 /* 制御点ナンバーから、テーブルオフセットに変換 */
838 pXM_INSTRUMENT->PanningSustainPoint
839 = pXM_INSTRUMENT->aPointsForPanningEnvelope[ pXM_INSTRUMENT->PanningSustainPoint ].x ;
840 pXM_INSTRUMENT->PanningLoopStartPoint
841 = pXM_INSTRUMENT->aPointsForPanningEnvelope[ pXM_INSTRUMENT->PanningLoopStartPoint ].x ;
842 pXM_INSTRUMENT->PanningLoopEndPoint
843 = pXM_INSTRUMENT->aPointsForPanningEnvelope[ pXM_INSTRUMENT->PanningLoopEndPoint ].x ;
845 /* ループ区間の長さが 0 の時は、ループを無効化 */
846 if( pXM_INSTRUMENT->PanningLoopStartPoint == pXM_INSTRUMENT->PanningLoopEndPoint ){
847 pXM_INSTRUMENT->PanningType &= ~ENV_LOOP ;
854 XM の妙なフォーマットの都合上、処理ステップを2つに分けなければならない。
860 for( idxLocalSample = 0
861 ; idxLocalSample < pXM_INSTRUMENT->NumberOfSamplesInInstrument
865 S32 idxSample = idxInst * MAX_SAMPLES_IN_INSTRUMENT + idxLocalSample ;
866 XM_SAMPLE *pXM_SAMPLE = XM_SAMPLE__Create( );
867 pMOD->apXM_SAMPLE[ idxSample ] = pXM_SAMPLE ;
870 if( pXM_SAMPLE == NULL ){
871 #if (WARNING_LEVEL >= 1)
872 LogMsg(pMOD->Instance,
873 "MOD__LoadSongAsXM : \n"
874 " XM_SAMPLE 構造体の確保に失敗しました。\n"
878 MOD__ReleaseSong( pMOD );
883 pXM_SAMPLE->SampleLength = (S32)*((S32*)&pMusDat[ ofs + 0 ]);
884 pXM_SAMPLE->SampleLoopStart = (S32)*((S32*)&pMusDat[ ofs + 4 ]);
885 pXM_SAMPLE->SampleLoopLength = (S32)*((S32*)&pMusDat[ ofs + 8 ]);
886 pXM_SAMPLE->Volume = (S32)*((U8*) &pMusDat[ ofs + 12 ]);
887 pXM_SAMPLE->FineTune = (S32)*((S8*) &pMusDat[ ofs + 13 ]);
888 pXM_SAMPLE->Type = (S32)*((U8*) &pMusDat[ ofs + 14 ]);
889 pXM_SAMPLE->Panning = (S32)*((U8*) &pMusDat[ ofs + 15 ]);
890 pXM_SAMPLE->RelativeNoteNumber = (S32)*((S8*) &pMusDat[ ofs + 16 ]);
891 pXM_SAMPLE->Reserved = (S32)*((U8*) &pMusDat[ ofs + 17 ]);
892 memcpy( &pXM_SAMPLE->aszSampleName[0] , &pMusDat[ ofs + 18 ] , 22 );
893 pXM_SAMPLE->aszSampleName[22] = 0 ; /* 文字列終点 */
894 ofs += pXM_INSTRUMENT->SampleHeaderSize ;
896 #if (WARNING_LEVEL >= 3)
897 LogMsg(pMOD->Instance,
898 "MOD__LoadSongAsXM : \n"
899 " pXM_SAMPLE->SampleLength %d \n"
900 " pXM_SAMPLE->SampleLoopStart %d \n"
901 " pXM_SAMPLE->SampleLoopLength %d \n"
902 " pXM_SAMPLE->Volume %d \n"
903 " pXM_SAMPLE->FineTune %d \n"
904 " pXM_SAMPLE->Type %d \n"
905 " pXM_SAMPLE->Panning %d \n"
906 " pXM_SAMPLE->RelativeNoteNumber %d \n"
907 " pXM_SAMPLE->Reserved %d \n"
908 " pXM_SAMPLE->aszSampleName %s \n"
909 ,pXM_SAMPLE->SampleLength
910 ,pXM_SAMPLE->SampleLoopStart
911 ,pXM_SAMPLE->SampleLoopLength
913 ,pXM_SAMPLE->FineTune
916 ,pXM_SAMPLE->RelativeNoteNumber
917 ,pXM_SAMPLE->Reserved
918 ,pXM_SAMPLE->aszSampleName
922 /* ループ区間の長さが 0 または、長さが 0 なら、ループを無効化 */
923 if( pXM_SAMPLE->SampleLoopLength == 0
924 || pXM_SAMPLE->SampleLength == 0
926 pXM_SAMPLE->Type &= ~(SMP_LOOP | SMP_PINGPONGLOOP);
927 pXM_SAMPLE->SampleLoopStart = 0 ;
928 pXM_SAMPLE->SampleLoopLength = 0 ;
931 if( pXM_SAMPLE->Type & (SMP_LOOP | SMP_PINGPONGLOOP) ){
933 if( pXM_SAMPLE->SampleLength < pXM_SAMPLE->SampleLoopStart + pXM_SAMPLE->SampleLoopLength ){
934 #if (WARNING_LEVEL >= 2)
935 LogMsg(pMOD->Instance,
936 "MOD__LoadSongAsXM : \n"
937 " サンプリングデータサイズと、ループ区間の長さの整合性が取れていません。\n"
941 MOD__ReleaseSong( pMOD );
946 /* ループ展開後のサンプリングデータの全長 */
947 reserve = pXM_SAMPLE->SampleLength ;
948 if( pXM_SAMPLE->Type & SMP_PINGPONGLOOP ) reserve += pXM_SAMPLE->SampleLoopLength ;
950 /* 必要なら、サンプリングデータ領域のメモリ確保 */
954 reserve は要素数でなくバイト長である点に注意。
956 void *pSampleData = AllocMemory( reserve + 512 );
957 pXM_SAMPLE->pSampleData = pSampleData ;
960 if( pSampleData == NULL ){
961 #if (WARNING_LEVEL >= 1)
962 LogMsg(pMOD->Instance,
963 "MOD__LoadSongAsXM : \n"
964 " サンプリングデータ読み込み先メモリの確保に失敗しました。\n"
968 MOD__ReleaseSong( pMOD );
972 pXM_SAMPLE->pSampleData = NULL ;
977 for( idxLocalSample = 0
978 ; idxLocalSample < pXM_INSTRUMENT->NumberOfSamplesInInstrument
981 S32 idxSample = idxInst * MAX_SAMPLES_IN_INSTRUMENT + idxLocalSample ;
982 XM_SAMPLE *pXM_SAMPLE = pMOD->apXM_SAMPLE[ idxSample ];
985 if( pXM_SAMPLE->pSampleData != NULL ){
987 if( lMusDat - ofs < pXM_SAMPLE->SampleLength ){
988 #if (WARNING_LEVEL >= 2)
989 LogMsg(pMOD->Instance,
990 "MOD__LoadSongAsXM : \n"
991 " データサイズが不足しています。サンプリングデータを読み込めません。\n"
995 MOD__ReleaseSong( pMOD );
1000 memcpy( pXM_SAMPLE->pSampleData , &pMusDat[ ofs ] , pXM_SAMPLE->SampleLength );
1001 ofs += pXM_SAMPLE->SampleLength ;
1003 pXM_SAMPLE->VoiceMode = VM_ON ;
1004 if( pXM_SAMPLE->Type & (SMP_LOOP | SMP_PINGPONGLOOP) ){
1005 pXM_SAMPLE->VoiceMode |= VM_LOOP ;
1010 オーバーフローが生じても、補正しないのが正しい。
1012 if( pXM_SAMPLE->Type & SMP_16BIT ){
1013 S32 Cnt = pXM_SAMPLE->SampleLength >> 1 ; /* 1要素2バイト */
1016 S16 *pScan = (S16 *)pXM_SAMPLE->pSampleData ;
1018 pXM_SAMPLE->VoiceMode |= VM_16BIT ;
1020 NewVal = *pScan + OldVal ;
1021 *pScan++ = (S16)NewVal ;
1025 S32 Cnt = pXM_SAMPLE->SampleLength ; /* 1要素1バイト */
1028 S8 *pScan = (S8 *)pXM_SAMPLE->pSampleData ;
1031 NewVal = *pScan + OldVal ;
1032 *pScan++ = (S8)NewVal ;
1038 if( pXM_SAMPLE->Type & SMP_PINGPONGLOOP ){
1039 pXM_SAMPLE->VoiceMode |= VM_LOOP ;
1040 if( pXM_SAMPLE->Type & SMP_16BIT ){
1041 S32 Cnt = pXM_SAMPLE->SampleLoopLength >> 1 ;
1042 S8 *pSampleData = reinterpret_cast<S8*>(pXM_SAMPLE->pSampleData);
1043 S16 *pSrc = reinterpret_cast<S16 *>(pSampleData
1044 + pXM_SAMPLE->SampleLoopStart
1045 + pXM_SAMPLE->SampleLoopLength
1047 S16 *pDst = reinterpret_cast<S16 *>(pSampleData
1048 + pXM_SAMPLE->SampleLoopStart
1049 + pXM_SAMPLE->SampleLoopLength
1052 while( Cnt-- > 0 ) *pDst++ = *pSrc-- ;
1054 S32 Cnt = pXM_SAMPLE->SampleLoopLength ;
1055 S8 *pSampleData = reinterpret_cast<S8*>(pXM_SAMPLE->pSampleData );
1056 S8 *pSrc = reinterpret_cast<S8 *>( pSampleData
1057 + pXM_SAMPLE->SampleLoopStart
1058 + pXM_SAMPLE->SampleLoopLength
1060 S8 *pDst = reinterpret_cast<S8 *>( pSampleData
1061 + pXM_SAMPLE->SampleLoopStart
1062 + pXM_SAMPLE->SampleLoopLength
1065 while( Cnt-- > 0 ) *pDst++ = *pSrc-- ;
1067 /* 展開したので、ループ区間の長さは2倍になる */
1068 pXM_SAMPLE->SampleLoopLength <<= 1 ;
1071 /* 16 BIT サンプルは、長さの単位を変換 */
1072 if( pXM_SAMPLE->Type & SMP_16BIT ){
1073 pXM_SAMPLE->SampleLength >>= 1 ;
1074 pXM_SAMPLE->SampleLoopStart >>= 1 ;
1075 pXM_SAMPLE->SampleLoopLength >>= 1 ;
1078 if( pXM_SAMPLE->VoiceMode & VM_LOOP ){
1079 /* SampleLength の再算出 */
1080 pXM_SAMPLE->SampleLength = pXM_SAMPLE->SampleLoopStart + pXM_SAMPLE->SampleLoopLength ;
1082 /* 線形補完の連続性のため、末端に1要素コピー */
1083 if( pXM_SAMPLE->Type & SMP_16BIT ){
1084 S16 *pSampleData = reinterpret_cast<S16*>(pXM_SAMPLE->pSampleData) ;
1085 pSampleData[ pXM_SAMPLE->SampleLength ] = pSampleData[ pXM_SAMPLE->SampleLoopStart ];
1087 S8 *pSampleData = reinterpret_cast<S8*>(pXM_SAMPLE->pSampleData) ;
1088 pSampleData[ pXM_SAMPLE->SampleLength ] = pSampleData[ pXM_SAMPLE->SampleLoopStart ];
1092 /* キーオフ時プチノイズ対策(波形の最終要素を徐々に減衰させる)*/
1093 if( pXM_SAMPLE->Type & SMP_16BIT ){
1094 S16 *pSampleData =reinterpret_cast<S16*>(pXM_SAMPLE->pSampleData );
1095 S32 LastVal_ = pSampleData[ pXM_SAMPLE->SampleLength - 1 ] << SFT ;
1097 for( i=0 ; i<256 ; i++ ){
1098 pSampleData[ pXM_SAMPLE->SampleLength + i ] = (S16)(LastVal_ >> SFT) ;
1099 LastVal_ -= LastVal_ >> 6 ;
1102 S8 *pSampleData = reinterpret_cast<S8*>(pXM_SAMPLE->pSampleData) ;
1103 S32 LastVal_ = pSampleData[ pXM_SAMPLE->SampleLength - 1 ] << SFT ;
1105 for( i=0 ; i<256 ; i++ ){
1106 pSampleData[ pXM_SAMPLE->SampleLength + i ] = (S8)(LastVal_ >> SFT) ;
1107 LastVal_ -= LastVal_ >> 6 ;
1110 pXM_SAMPLE->SampleLength += 255 ; /* 1 要素の余裕を持たせる */
1116 /* 全 Note 対応のサンプリングデータへのポインターをここで先に求めておく */
1119 for( idxNote = 0 ; idxNote <= 95 ; idxNote++ ){
1120 S32 idxSample = pXM_INSTRUMENT->aSampleNumberForAllNotes[ idxNote ];
1123 && idxSample < MAX_SAMPLES_IN_INSTRUMENT
1125 pXM_INSTRUMENT->apAllNoteXM_SAMPLE[ idxNote ]
1126 = pMOD->apXM_SAMPLE[ idxInst * MAX_SAMPLES_IN_INSTRUMENT + idxSample ];
1128 pXM_INSTRUMENT->apAllNoteXM_SAMPLE[ idxNote ] = NULL ;
1141 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1146 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
1147 static S32 MOD__LoadSongAsMOD(
1152 U8 *pMusDat = reinterpret_cast<U8*>(pMusDat_) ;
1156 if( pMOD == NULL ) return( FALSE );
1159 if( lMusDat < 1080+4 ){
1160 #if (WARNING_LEVEL >= 2)
1161 LogMsg(pMOD->Instance,
1162 "MOD__LoadSongAsMOD : \n"
1163 " データサイズが不足しています。\n"
1167 MOD__ReleaseSong( pMOD );
1172 memcpy( &pMOD->XmId.aszModuleName[0] , &pMusDat[ ofs + 0 ] , 20 );
1173 pMOD->XmId.aszModuleName[19] = 0 ; /* 文字列終点 */
1176 #if (WARNING_LEVEL >= 2)
1177 LogMsg(pMOD->Instance,
1178 "MOD__LoadSongAsMOD : ModName = %s \n"
1179 ,pMOD->XmId.aszModuleName
1184 フォーマット識別から、サンプリングデータ総数と、総チャンネル数を知る。
1185 識別子が無い場合は、この位置がパターンデータの出発点となり、
1186 サンプリングデータは 15 種類となるが、そのような古いデータには対応しない。
1190 const char *pszExt ;
1194 { "M.K." , 4 , 31 } /* protracker 4 channel */
1195 ,{ "M!K!" , 4 , 31 } /* protracker 4 channel(パターンの Row 数が可変らしい?)*/
1196 ,{ "M&K!" , 4 , 31 }
1197 ,{ "FLT4" , 4 , 31 } /* startracker 4 channel */
1198 ,{ "FLT8" , 4 , 31 } /* 怪しいが、4ch 扱いとするらしい。*/
1199 ,{ "N.T." , 4 , 15 } /* 古い 0xFxx コマンドによるテンポ設定を有効にしなければならない */
1200 ,{ "CD81" , 8 , 31 } /* atari oktalyzer 8 channel */
1201 ,{ "OKTA" , 8 , 31 } /* atari oktalyzer 8 channel */
1202 ,{ "TDZ1" , 1 , 31 }
1203 ,{ "TDZ2" , 2 , 31 }
1204 ,{ "TDZ3" , 3 , 31 }
1205 ,{ "TDZ4" , 4 , 31 }
1206 ,{ "TDZ5" , 5 , 31 }
1207 ,{ "TDZ6" , 6 , 31 }
1208 ,{ "TDZ7" , 7 , 31 }
1209 ,{ "TDZ8" , 8 , 31 }
1210 ,{ "TDZ9" , 9 , 31 }
1211 ,{ "1CHN" , 1 , 31 }
1212 ,{ "2CHN" , 2 , 31 }
1213 ,{ "3CHN" , 3 , 31 }
1214 ,{ "4CHN" , 4 , 31 } /* fasttracker 4 channel */
1215 ,{ "5CHN" , 5 , 31 }
1216 ,{ "6CHN" , 6 , 31 } /* fasttracker 6 channel */
1217 ,{ "7CHN" , 7 , 31 }
1218 ,{ "8CHN" , 8 , 31 } /* fasttracker 8 channel */
1219 ,{ "9CHN" , 9 , 31 }
1220 ,{ "10CH" ,10 , 31 }
1221 ,{ "11CH" ,11 , 31 }
1222 ,{ "12CH" ,12 , 31 }
1223 ,{ "13CH" ,13 , 31 }
1224 ,{ "14CH" ,14 , 31 }
1225 ,{ "15CH" ,15 , 31 }
1226 ,{ "16CH" ,16 , 31 }
1227 ,{ "17CH" ,17 , 31 }
1228 ,{ "18CH" ,18 , 31 }
1229 ,{ "19CH" ,19 , 31 }
1230 ,{ "20CH" ,20 , 31 }
1231 ,{ "21CH" ,21 , 31 }
1232 ,{ "22CH" ,22 , 31 }
1233 ,{ "23CH" ,23 , 31 }
1234 ,{ "24CH" ,24 , 31 }
1235 ,{ "25CH" ,25 , 31 }
1236 ,{ "26CH" ,26 , 31 }
1237 ,{ "27CH" ,27 , 31 }
1238 ,{ "28CH" ,28 , 31 }
1239 ,{ "29CH" ,29 , 31 }
1240 ,{ "30CH" ,30 , 31 }
1241 ,{ "31CH" ,31 , 31 }
1242 ,{ "32CH" ,32 , 31 }
1243 ,{ "16CN" ,16 , 31 } /* taketracker 16 channel */
1244 ,{ "32CN" ,32 , 31 } /* taketracker 32 channel */
1249 #if (WARNING_LEVEL >= 2)
1252 aExt[0] = pMusDat[1080] ;
1253 aExt[1] = pMusDat[1081] ;
1254 aExt[2] = pMusDat[1082] ;
1255 aExt[3] = pMusDat[1083] ;
1258 LogMsg(pMOD->Instance,
1259 "MOD__LoadSongAsMOD : +1080 識別子 = [%s] \n"
1268 if( ExtInfo[ i ].pszExt == NULL ){
1269 #if (WARNING_LEVEL >= 2)
1270 LogMsg(pMOD->Instance,
1271 "MOD__LoadSongAsMOD : "
1272 " 不明な +1080 識別子です。読み込みをキャンセルします。\n"
1275 MOD__ReleaseSong( pMOD );
1279 /* 識別子が一致したら、認識成功 */
1280 if( pMusDat[1080] == ExtInfo[ i ].pszExt[0]
1281 && pMusDat[1081] == ExtInfo[ i ].pszExt[1]
1282 && pMusDat[1082] == ExtInfo[ i ].pszExt[2]
1283 && pMusDat[1083] == ExtInfo[ i ].pszExt[3]
1285 pMOD->XmHeader.NumberOfChannels = ExtInfo[ i ].idxChannel ;
1286 pMOD->XmHeader.NumberOfInstruments = ExtInfo[ i ].idxInst ;
1287 #if (WARNING_LEVEL >= 3)
1288 LogMsg(pMOD->Instance,
1289 "MOD__LoadSongAsMOD : \n"
1290 " +1080 識別子の認識に成功しました。\n"
1291 " チャンネル数 = %d , サンプリングデータ数 = %d \n"
1292 ,pMOD->XmHeader.NumberOfChannels
1293 ,pMOD->XmHeader.NumberOfInstruments
1304 /* サンプリングデータの情報を取得 */
1309 for( idxInst = 0 ; idxInst < pMOD->XmHeader.NumberOfInstruments ; idxInst++ ){
1310 S32 idxSample = idxInst * MAX_SAMPLES_IN_INSTRUMENT ;
1311 XM_SAMPLE *pXM_SAMPLE ;
1313 /* XM_SAMPLE 構造体の確保 */
1314 pMOD->apXM_SAMPLE[ idxSample ] = pXM_SAMPLE = XM_SAMPLE__Create( );
1317 if( pXM_SAMPLE == NULL ){
1318 #if (WARNING_LEVEL >= 1)
1319 LogMsg(pMOD->Instance,
1320 "MOD__LoadSongAsMOD : \n"
1321 " XM_SAMPLE 構造体の確保に失敗しました。\n"
1325 MOD__ReleaseSong( pMOD );
1329 /* XM_SAMPLE 構造体の初期化 */
1331 pXM_SAMPLE->Type = 0 ;
1332 pXM_SAMPLE->Panning = 0x80 ;
1333 pXM_SAMPLE->RelativeNoteNumber = 0 ;
1334 pXM_SAMPLE->Reserved = 0 ;
1336 /* サンプリングデータの名前を取得 */
1337 memcpy( &pXM_SAMPLE->aszSampleName[0] , &pMusDat[ ofs ] , 21 );
1338 pXM_SAMPLE->aszSampleName[21] = 0 ; /* 文字列終点 */
1345 pXM_SAMPLE->SampleLength = (U32)( ((U32)pMusDat[ ofs + 0 ] << 8)
1346 | ((U32)pMusDat[ ofs + 1 ] << 0) );
1347 pXM_SAMPLE->SampleLength *= 2 ;
1355 S32 Val = pMusDat[ ofs ] & 15 ;
1359 pXM_SAMPLE->FineTune = Val << 4 ;
1363 /* サンプリングデータのデフォルト音量( 0 - 64 の値)*/
1364 pXM_SAMPLE->Volume = pMusDat[ ofs ];
1371 pXM_SAMPLE->SampleLoopStart = (S32)( ((U32)pMusDat[ ofs + 0 ] << 8)
1372 |((U32)pMusDat[ ofs + 1 ] << 0) );
1373 pXM_SAMPLE->SampleLoopStart *= 2 ;
1380 pXM_SAMPLE->SampleLoopLength = (S32)( ((U32)pMusDat[ ofs + 0 ] << 8)
1381 | ((U32)pMusDat[ ofs + 1 ] << 0) );
1382 pXM_SAMPLE->SampleLoopLength *= 2 ;
1385 /* サンプリングのループ再生有無の判定 */
1386 if( pXM_SAMPLE->SampleLoopLength <= 2
1387 || pXM_SAMPLE->SampleLength == 0
1389 pXM_SAMPLE->Type &= ~(SMP_LOOP | SMP_PINGPONGLOOP);
1390 pXM_SAMPLE->SampleLoopStart = 0 ;
1391 pXM_SAMPLE->SampleLoopLength = 0 ;
1393 pXM_SAMPLE->Type |= SMP_LOOP ;
1396 if( pXM_SAMPLE->SampleLength < pXM_SAMPLE->SampleLoopStart + pXM_SAMPLE->SampleLoopLength ){
1397 #if (WARNING_LEVEL >= 2)
1398 LogMsg(pMOD->Instance,
1399 "MOD__LoadSongAsMOD : \n"
1400 " サンプリングデータサイズと、ループ区間の長さの整合性が取れていません。\n"
1404 MOD__ReleaseSong( pMOD );
1410 #if (WARNING_LEVEL >= 3)
1411 LogMsg(pMOD->Instance,
1412 "MOD__LoadSongAsMOD : \n"
1413 " pXM_SAMPLE->SampleLength %d \n"
1414 " pXM_SAMPLE->SampleLoopStart %d \n"
1415 " pXM_SAMPLE->SampleLoopLength %d \n"
1416 " pXM_SAMPLE->Volume %d \n"
1417 " pXM_SAMPLE->FineTune %d \n"
1418 " pXM_SAMPLE->Type %d \n"
1419 " pXM_SAMPLE->Panning %d \n"
1420 " pXM_SAMPLE->RelativeNoteNumber %d \n"
1421 " pXM_SAMPLE->Reserved %d \n"
1422 " pXM_SAMPLE->aszSampleName %s \n"
1423 ,pXM_SAMPLE->SampleLength
1424 ,pXM_SAMPLE->SampleLoopStart
1425 ,pXM_SAMPLE->SampleLoopLength
1427 ,pXM_SAMPLE->FineTune
1429 ,pXM_SAMPLE->Panning
1430 ,pXM_SAMPLE->RelativeNoteNumber
1431 ,pXM_SAMPLE->Reserved
1432 ,pXM_SAMPLE->aszSampleName
1439 for( idxInst = 0 ; idxInst < pMOD->XmHeader.NumberOfInstruments ; idxInst++ ){
1440 S32 idxSample = idxInst * MAX_SAMPLES_IN_INSTRUMENT ;
1441 XM_INSTRUMENT *pXM_INSTRUMENT ;
1443 /* XM_INSTRUMENT 構造体の確保 */
1444 pMOD->apXM_INSTRUMENT[ idxInst ] = pXM_INSTRUMENT = XM_INSTRUMENT__Create( );
1447 if( pXM_INSTRUMENT == NULL ){
1448 #if (WARNING_LEVEL >= 1)
1449 LogMsg(pMOD->Instance,
1450 "MOD__LoadSongAsMOD : \n"
1451 " XM_INSTRUMENT 構造体の確保に失敗しました。\n"
1455 MOD__ReleaseSong( pMOD );
1459 /* XM_INSTRUMENT 構造体の初期化 */
1461 pXM_INSTRUMENT->InstrumentSize = 0 ;
1462 pXM_INSTRUMENT->aszInstrumentName[0] = 0 ;
1463 pXM_INSTRUMENT->InstrumentType = 0 ;
1464 pXM_INSTRUMENT->NumberOfSamplesInInstrument = 1 ;
1465 pXM_INSTRUMENT->SampleHeaderSize = 0 ;
1466 for( i=0 ; i<96 ; i++ ){
1467 pXM_INSTRUMENT->aSampleNumberForAllNotes[i] = (U8)idxInst ;
1469 for( i=0 ; i<12 ; i++ ){
1470 pXM_INSTRUMENT->aPointsForVolumeEnvelope[i].x = 0 ;
1471 pXM_INSTRUMENT->aPointsForVolumeEnvelope[i].y = 0 ;
1472 pXM_INSTRUMENT->aPointsForPanningEnvelope[i].x = 0 ;
1473 pXM_INSTRUMENT->aPointsForPanningEnvelope[i].y = 0 ;
1475 pXM_INSTRUMENT->NumberOfVolumePoints = 0 ;
1476 pXM_INSTRUMENT->NumberOfPanningPoints = 0 ;
1477 pXM_INSTRUMENT->VolumeSustainPoint = 0 ;
1478 pXM_INSTRUMENT->VolumeLoopStartPoint = 0 ;
1479 pXM_INSTRUMENT->VolumeLoopEndPoint = 0 ;
1480 pXM_INSTRUMENT->PanningSustainPoint = 0 ;
1481 pXM_INSTRUMENT->PanningLoopStartPoint = 0 ;
1482 pXM_INSTRUMENT->PanningLoopEndPoint = 0 ;
1483 pXM_INSTRUMENT->VolumeType = 0 ;
1484 pXM_INSTRUMENT->PanningType = 0 ;
1485 pXM_INSTRUMENT->AutoVibratoType = 0 ;
1486 pXM_INSTRUMENT->AutoVibratoSweep = 0 ;
1487 pXM_INSTRUMENT->AutoVibratoDepth = 0 ;
1488 pXM_INSTRUMENT->AutoVibratoRate = 0 ;
1489 pXM_INSTRUMENT->VolumeFadeout = 0 ;
1490 pXM_INSTRUMENT->Reserved = 0 ;
1492 for( i=0 ; i<96 ; i++ ){
1493 pXM_INSTRUMENT->apAllNoteXM_SAMPLE[ i ] = pMOD->apXM_SAMPLE[ idxSample ];
1495 for( i=0 ; i<325 ; i++ ){
1496 pXM_INSTRUMENT->VolumeEnvelopeTable[ i ] = 0 ;
1497 pXM_INSTRUMENT->PanningEnvelopeTable[ i ] = 0 ;
1504 /* オーダーテーブルの全長(1 ~ 128)*/
1505 pMOD->XmHeader.SongLength = pMusDat[ ofs ];
1509 NoiseTracker がオーダーテーブルのリピートポイントとしたバイト。
1510 ProTracker モジュールでは無意味なので、スキップする。
1515 /* パターンオーダーテーブルと、パターンデータの取得 */
1521 /* パターンオーダーテーブルの取得(MOD 形式では、128 byte 固定)*/
1522 memcpy( &pMOD->XmHeader.aPatternOrderTable[0] , &pMusDat[ ofs ] , 128 );
1525 /* パターンオーダーテーブル中の最大の値が、総パターンデータ数である。*/
1526 pMOD->XmHeader.NumberOfPatterns = 0 ;
1527 for( i=0 ; i<=127 ; i++ ){
1528 if( pMOD->XmHeader.NumberOfPatterns < pMOD->XmHeader.aPatternOrderTable[i] + 1 ){
1529 pMOD->XmHeader.NumberOfPatterns = pMOD->XmHeader.aPatternOrderTable[i] + 1 ;
1533 #if (WARNING_LEVEL >= 3)
1534 LogMsg(pMOD->Instance,
1535 "MOD__LoadSongAsMOD : \n"
1536 " pMOD->XmHeader.NumberOfPatterns = %d \n"
1537 ,pMOD->XmHeader.NumberOfPatterns
1541 /* +1080 フォーマット識別子をスキップ */
1545 if( lMusDat - ofs < pMOD->XmHeader.NumberOfChannels
1546 * pMOD->XmHeader.NumberOfPatterns
1547 * 64 /* MOD 形式では、パターンデータは 64 Row */
1550 #if (WARNING_LEVEL >= 3)
1551 LogMsg(pMOD->Instance,
1552 "MOD__LoadSongAsMOD : \n"
1553 " データサイズが不足しています。パターンデータを読み込めません。\n"
1557 MOD__ReleaseSong( pMOD );
1561 for( idxPattern = 0 ; idxPattern < pMOD->XmHeader.NumberOfPatterns ; idxPattern++ ){
1562 XM_PATTERN *pXM_PATTERN ;
1564 /* XM_PATTERN 構造体の確保 */
1565 pMOD->apXM_PATTERN[ idxPattern ] = pXM_PATTERN = XM_PATTERN__Create( );
1568 if( pXM_PATTERN == NULL ){
1569 #if (WARNING_LEVEL >= 1)
1570 LogMsg(pMOD->Instance,
1571 "MOD__LoadSongAsMOD : \n"
1572 " XM_PATTERN 構造体の確保に失敗しました。\n"
1576 MOD__ReleaseSong( pMOD );
1580 /* XM_PATTERN 構造体の初期化 */
1582 pXM_PATTERN->PatternHeaderLength = 0 ;
1583 pXM_PATTERN->PackingType = 0 ;
1584 pXM_PATTERN->NumberOfRowsInPattern = 64 ; /* MOD 形式では、パターンデータは 64 Row */
1585 pXM_PATTERN->PackedPatterndataSize = 0 ;
1587 pXM_PATTERN->pPatternData
1588 = reinterpret_cast<U8*>(AllocMemory( pMOD->XmHeader.NumberOfChannels * pXM_PATTERN->NumberOfRowsInPattern * 5 ));
1590 if( pXM_PATTERN->pPatternData == NULL ){
1591 #if (WARNING_LEVEL >= 1)
1592 LogMsg(pMOD->Instance,
1593 "MOD__LoadSongAsMOD : 異常事態発生 \n"
1594 " パターンデータ領域の確保に失敗しました。\n"
1598 MOD__ReleaseSong( pMOD );
1604 MOD 形式 -> XM 形式の変換を行いつつ読み込む。
1605 MOD 形式のパターンデータは、1チャンネル当たり、Row数 * 4 バイトで構成される。
1606 XM 形式のパターンデータは、1チャンネル当たり、Row数 * 5 バイトで構成される。
1608 for( idxRow = 0 ; idxRow < pXM_PATTERN->NumberOfRowsInPattern ; idxRow++ ){
1609 for( idxCannel = 0 ; idxCannel < pMOD->XmHeader.NumberOfChannels ; idxCannel++ ){
1610 static const S32 _aPeriodTable[] =
1612 0x6B0,0x650,0x5F5,0x5A0,0x54F,0x503,0x4BB,0x477,0x436,0x3FA,0x3C1,0x38B, /* Octave 0 */
1613 0x358,0x328,0x2FB,0x2D0,0x2A7,0x281,0x25D,0x23B,0x21B,0x1FD,0x1E0,0x1C5, /* Octave 1 */
1614 0x1AC,0x194,0x17D,0x168,0x154,0x141,0x12F,0x11E,0x10E,0x0FE,0x0F0,0x0E3, /* Octave 2 */
1615 0x0D6,0x0CA,0x0BF,0x0B4,0x0AA,0x0A0,0x097,0x08F,0x087,0x07F,0x078,0x071, /* Octave 3 */
1616 0x06B,0x065,0x05F,0x05A,0x055,0x050,0x04C,0x047,0x043,0x040,0x03C,0x039, /* Octave 4 */
1617 0x035,0x032,0x030,0x02D,0x02A,0x028,0x026,0x024,0x022,0x020,0x01E,0x01C, /* Octave 5 */
1618 0x01B,0x019,0x018,0x016,0x015,0x014,0x013,0x012,0x011,0x010,0x00F,0x00E /* Octave 6 */
1621 S32 idxInst = ((pMusDat[ ofs + 2 ] >> 4) & 0x0F) | (pMusDat[ ofs + 0 ] & 0xF0) ;
1622 S32 Period = pMusDat[ ofs + 1 ] | ((pMusDat[ ofs + 0 ] & 0x0F) << 8) ;
1623 S32 Command = pMusDat[ ofs + 2 ] & 0x0F ;
1624 S32 Param = pMusDat[ ofs + 3 ];
1627 S32 VolumeColumn= 0 ;
1630 /* Period -> Key 変換(テーブルから、最も近そうな値を検索)*/
1632 for( i = 0 ; i <= 7*12-2 ; i++ ){
1633 if( Period >= _aPeriodTable[i] + ((_aPeriodTable[i+1] - _aPeriodTable[i]) >> 1) ){
1642 MOD 形式では、音色指定を行う時、Volume column にデフォルト音量を
1646 XM_SAMPLE *pXM_SAMPLE = pMOD->apXM_SAMPLE[ MAX_SAMPLES_IN_INSTRUMENT * (idxInst - 1) ];
1647 if( pXM_SAMPLE != NULL ){
1648 VolumeColumn = pXM_SAMPLE->Volume + 0x10 ;
1654 S32 zxc = (idxRow * pMOD->XmHeader.NumberOfChannels + idxCannel) * 5 ;
1655 pXM_PATTERN->pPatternData[ zxc + 0 ] = (U8)idxKey ;
1656 pXM_PATTERN->pPatternData[ zxc + 1 ] = (U8)idxInst ;
1657 pXM_PATTERN->pPatternData[ zxc + 2 ] = (U8)VolumeColumn ;
1658 pXM_PATTERN->pPatternData[ zxc + 3 ] = (U8)Command ;
1659 pXM_PATTERN->pPatternData[ zxc + 4 ] = (U8)Param ;
1667 /* 有効なパターンデータ数分、有効なポインターを割り当て、それ以降は NULL とする。*/
1668 for( idxPattern = pMOD->XmHeader.NumberOfPatterns ; idxPattern < MAX_PATTERNS ; idxPattern++ ){
1669 pMOD->apXM_PATTERN[ idxPattern ] = NULL ;
1674 /* サンプリングデータの読みこみ */
1678 for( idxInst = 0 ; idxInst < pMOD->XmHeader.NumberOfInstruments ; idxInst++ ){
1679 XM_SAMPLE *pXM_SAMPLE = pMOD->apXM_SAMPLE[ MAX_SAMPLES_IN_INSTRUMENT * idxInst ];
1681 if( pXM_SAMPLE != NULL ){
1682 S32 len = pXM_SAMPLE->SampleLength ;
1686 if( lMusDat - ofs < len ){
1687 #if (WARNING_LEVEL >= 2)
1688 LogMsg(pMOD->Instance,
1689 "MOD__LoadSongAsMOD : \n"
1690 " データサイズが不足しています。サンプリングデータを読み込めません。\n"
1694 MOD__ReleaseSong( pMOD );
1698 /* メモリ確保(プチノイズ対策のため、余分に確保)。*/
1699 pXM_SAMPLE->pSampleData = AllocMemory( len + 256 );
1701 if( pXM_SAMPLE->pSampleData == NULL ){
1702 #if (WARNING_LEVEL >= 1)
1703 LogMsg(pMOD->Instance,
1704 "MOD__LoadSongAsMOD : 異常事態発生 \n"
1705 " サンプリングデータ領域の確保に失敗しました。\n"
1709 MOD__ReleaseSong( pMOD );
1713 #if (WARNING_LEVEL >= 3)
1714 LogMsg(pMOD->Instance,
1715 "MOD__LoadSongAsMOD : \n"
1716 " サンプリングデータ %d 読みこみ。len = %d \n"
1722 memcpy( pXM_SAMPLE->pSampleData , &pMusDat[ ofs ] , len );
1725 pXM_SAMPLE->VoiceMode = VM_ON ;
1727 if( pXM_SAMPLE->Type & SMP_LOOP ){
1728 pXM_SAMPLE->VoiceMode |= VM_LOOP ;
1730 /* SampleLength の再算出 */
1731 pXM_SAMPLE->SampleLength = pXM_SAMPLE->SampleLoopStart + pXM_SAMPLE->SampleLoopLength ;
1733 /* 線形補完の連続性のため、末端に1要素コピー */
1735 S8 *pSampleData = (S8*)pXM_SAMPLE->pSampleData ;
1736 pSampleData[ pXM_SAMPLE->SampleLength ] = pSampleData[ pXM_SAMPLE->SampleLoopStart ];
1740 /* キーオフ時プチノイズ対策(波形の最終要素を徐々に減衰させる)*/
1741 S8 *pSampleData = (S8*)pXM_SAMPLE->pSampleData ;
1742 S32 LastVal_ = pSampleData[ pXM_SAMPLE->SampleLength - 1 ] << SFT ;
1744 for( i=0 ; i<256 ; i++ ){
1745 pSampleData[ pXM_SAMPLE->SampleLength + i ] = (S8)(LastVal_ >> SFT) ;
1746 LastVal_ -= LastVal_ >> 6 ;
1749 pXM_SAMPLE->SampleLength += 255 ; /* 1 要素の余裕を持たせる */
1757 pMOD->XmId.aszID_Text[0] = 0 ; /* 文字列終点 */
1758 pMOD->XmId.ID_Byte = 0 ; /* ダミー */
1759 pMOD->XmId.aszTrackerName[0] = 0 ; /* 文字列終点 */
1760 pMOD->XmId.VersionNumber = 0 ; /* ダミー */
1761 pMOD->XmHeader.HeaderSize = 0 ; /* ダミー */
1762 pMOD->XmHeader.RestartPosition = 0 ; /* ダミー */
1763 pMOD->XmHeader.Flags = 0 ;
1764 pMOD->XmHeader.DefaultTempo = 6 ;
1765 pMOD->XmHeader.DefaultBPM = 125 ;
1772 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1777 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
1779 MOD *pMOD /* this ポインター */
1780 ,void *pMusDat_ /* メモリ上にファイルを読み込み、そのポインターをここに指定 */
1781 ,S32 lMusDat /* データサイズ */
1783 if( pMOD == NULL ) return( FALSE );
1786 MOD__ReleaseSong( pMOD );
1789 if( MOD__LoadSongAsXM( pMOD , pMusDat_ , lMusDat ) ){
1790 pMOD->FormatType = TYPE_XM ;
1791 MOD__InitPlay( pMOD );
1793 #if (WARNING_LEVEL >= 2)
1794 LogMsg(pMOD->Instance,
1795 "MOD__LoadSong : XM 形式として読み込みました。\n"
1803 if( MOD__LoadSongAsMOD( pMOD , pMusDat_ , lMusDat ) ){
1804 pMOD->FormatType = TYPE_MOD ;
1805 MOD__InitPlay( pMOD );
1807 #if (WARNING_LEVEL >= 2)
1808 LogMsg(pMOD->Instance,
1809 "MOD__LoadSong : MOD 形式として読み込みました。\n"
1817 pMOD->FormatType = TYPE_NOTAVAILABLE ;
1823 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1828 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
1829 S32 MOD__ReleaseSong(
1830 MOD *pMOD /* this ポインター */
1834 if( pMOD == NULL ) return( FALSE );
1836 for( i=0 ; i<MAX_PATTERNS ; i++ ){
1837 if( pMOD->apXM_PATTERN[i] != NULL ){
1838 XM_PATTERN__Destruct( pMOD->apXM_PATTERN[i] );
1839 pMOD->apXM_PATTERN[i] = NULL ;
1843 for( i=0 ; i<MAX_INSTRUMENTS ; i++ ){
1844 if( pMOD->apXM_INSTRUMENT[i] != NULL ){
1845 XM_INSTRUMENT__Destruct( pMOD->apXM_INSTRUMENT[i] );
1846 pMOD->apXM_INSTRUMENT[i] = NULL ;
1850 for( i=0 ; i<MAX_SAMPLES ; i++ ){
1851 if( pMOD->apXM_SAMPLE[i] != NULL ){
1852 XM_SAMPLE__Destruct( pMOD->apXM_SAMPLE[i] );
1853 pMOD->apXM_SAMPLE[i] = NULL ;
1857 pMOD->FormatType = TYPE_NOTAVAILABLE ;
1864 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1868 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
1869 static S32 MOD__KeyToPeriod_(
1876 if( pMOD == NULL ) return( FALSE );
1878 if( Key < 0 ) Key = 0 ;
1879 if( Key > 118 ) Key = 118 ;
1881 if( pMOD->XmHeader.Flags & LINEAR_FREQUENCY ){
1883 Period_ = ((10*12*16*4 - Key*16*4) << SFT) - (FineTune << (SFT - 1)) ;
1887 /* AmigaPeriod モード */
1888 static const U32 aAmigaFreqTable[] =
1890 907, 900, 894, 887, 881, 875, 868, 862, 856, 850, 844, 838, 832, 826, 820, 814
1891 , 808, 802, 796, 791, 785, 779, 774, 768, 762, 757, 752, 746, 741, 736, 730, 725
1892 , 720, 715, 709, 704, 699, 694, 689, 684, 678, 675, 670, 665, 660, 655, 651, 646
1893 , 640, 636, 632, 628, 623, 619, 614, 610, 604, 601, 597, 592, 588, 584, 580, 575
1894 , 570, 567, 563, 559, 555, 551, 547, 543, 538, 535, 532, 528, 524, 520, 516, 513
1895 , 508, 505, 502, 498, 494, 491, 487, 484, 480, 477, 474, 470, 467, 463, 460, 457
1896 , 453, 450, 447, 443, 440, 437, 434, 431, 428
1898 S32 offset = (Key % 12) << 3 ;
1899 S32 nShift = Key / 12 ;
1904 if( FineTune >= 0 ){
1905 RoughFineTune = FineTune / 16 ;
1906 FineFineTune = FineTune & 15 ;
1908 RoughFineTune = (FineTune - 15) / 16 ;
1909 FineFineTune = FineTune & 15 ;
1912 Val = ( aAmigaFreqTable[ 8 + offset + RoughFineTune ] * (16 - FineFineTune)
1913 + aAmigaFreqTable[ 9 + offset + RoughFineTune ] * FineFineTune
1917 if( nShift > 0 ) Val >>= nShift ;
1918 if( nShift < 0 ) Val <<= -nShift ;
1926 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1930 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
1931 static S32 MOD__Period_ToKey(
1936 if( pMOD == NULL ) return( FALSE );
1938 if( pMOD->XmHeader.Flags & LINEAR_FREQUENCY ){
1940 S32 Key = ( (10*12*16*4 << SFT) - (FineTune << (SFT - 1)) - Period_
1941 + (16*4 << SFT)/2 /* 四捨五入 */
1946 /* AmigaPeriod モード */
1949 S32 Min = 0x7FFFFFFF ;
1951 for( Key = 0 ; Key <= 118 ; Key++ ){
1952 S32 zxc = abs( Period_ - MOD__KeyToPeriod_( pMOD , Key , FineTune ) );
1966 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1971 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
1972 S32 MOD__Set_Volume(
1973 MOD *pMOD /* this ポインター */
1974 ,S32 Volume /* 音量 0 ~ 256(それ以上にも設定可能)*/
1976 if( pMOD == NULL ) return( FALSE );
1978 if( Volume <= 0 ) Volume = 0 ; /* 無効な値を回避 */
1979 pMOD->GlobalVolumeScale_ = ONE * Volume >> 8 ;
1986 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1991 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
1992 S32 MOD__Set_nWavePerSec(
1993 MOD *pMOD /* this ポインター */
1994 ,S32 nWavePerSec /* WAVE 出力デバイスの周波数(Hz) */
1996 if( pMOD == NULL ) return( FALSE );
1998 if( nWavePerSec <= 0 ) nWavePerSec = 44100 ; /* 無効な値を回避 */
1999 pMOD->nWavePerSec = nWavePerSec ;
2006 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2007 ▼ ループ再生モード / 非ループ再生モード の指定
2011 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
2012 S32 MOD__Set_bLoopMode(
2013 MOD *pMOD /* this ポインター */
2014 ,S32 bLoopMode /* ループ再生モードか? TRUE / FALSE */
2016 if( pMOD == NULL ) return( FALSE );
2018 pMOD->bLoopMode = bLoopMode ;
2025 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2026 ▼ 自動ゲインコントロールするかどうか の指定
2030 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
2031 S32 MOD__Set_bAutoGainControl(
2032 MOD *pMOD /* this ポインター */
2033 ,S32 bAutoGainControl /* 自動ゲインコントロールするか? TRUE / FALSE */
2035 if( pMOD == NULL ) return( FALSE );
2037 pMOD->bAutoGainControl = bAutoGainControl ;
2044 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2045 ▼ PatternLoop の復帰点を、パターンの先頭に設置
2047 パターン切り替わり時に、必ず実行すること。
2048 コマンド E6x にて、復帰点を設置しない場合の対策である。
2052 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
2053 static S32 MOD__InitPatternLoop(
2058 if( pMOD == NULL ) return( FALSE );
2061 for( i=0 ; i<MAX_CHANNELS ; i++ ){
2062 CHANSTAT *pCHANSTAT = &(pMOD->aCHANSTAT[ i ]);
2063 pCHANSTAT->PatternLoopRow = 0 ;
2064 pCHANSTAT->PatternLoopCount = 0 ;
2072 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2073 ▼ 再生を初期化(内部パラメーターを初期化し、先頭から再生し直す)
2077 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
2079 MOD *pMOD /* this ポインター */
2083 if( pMOD == NULL ) return( FALSE );
2085 if( pMOD->FormatType == TYPE_NOTAVAILABLE ) return( FALSE );
2087 pMOD->bDone = FALSE ;
2089 pMOD->TickCount = 0 ;
2090 pMOD->nTickPerRow = pMOD->XmHeader.DefaultTempo ;
2091 pMOD->BPM = pMOD->XmHeader.DefaultBPM ;
2092 pMOD->nWavePerTick = (pMOD->nWavePerSec * 5) / (pMOD->BPM * 2);
2093 pMOD->nRestWave = 0 ;
2096 pMOD->BreakSequence = -1 ;
2097 pMOD->BreakRow = -1 ;
2098 pMOD->PatternDelay = 0 ;
2099 pMOD->FinePatternDelay = 0 ;
2101 pMOD->idxSequenceData = 0 ;
2103 pMOD->GlobalVolume_ = 0x40 << SFT ;
2104 pMOD->GlobalVolumeSlide = 0 ;
2105 pMOD->GainControlScale_ = ONE ;
2107 pMOD->AntiNoiseVal_L = 0 ;
2108 pMOD->AntiNoiseVal_R = 0 ;
2112 for( i=0 ; i<MAX_CHANNELS ; i++ ){
2113 CHANSTAT *pCHANSTAT = &(pMOD->aCHANSTAT[ i ]);
2115 pCHANSTAT->idxNowPatternNote = -1 ;
2116 pCHANSTAT->idxNowRealNote = -1 ;
2117 pCHANSTAT->NowVolumeColumn = 0 ;
2118 pCHANSTAT->NowCommand = 0 ;
2119 pCHANSTAT->NowParam = 0 ;
2120 pCHANSTAT->NowPeriod_ = 0 ;
2121 pCHANSTAT->idxNowInst = -1 ;
2123 pCHANSTAT->pPendingXM_INSTRUMENT = NULL ;
2124 pCHANSTAT->pPlayingXM_INSTRUMENT = NULL ;
2125 pCHANSTAT->pPlayingXM_SAMPLE = NULL ;
2127 pCHANSTAT->idxLastRealNote = 0 ;
2129 pCHANSTAT->PendingPeriod_ = 0 ;
2130 pCHANSTAT->PlayingPeriod_ = 0 ;
2131 pCHANSTAT->FinalPeriod_ = 0 ;
2132 pCHANSTAT->PeriodLowLimit_ = 0 ;
2133 pCHANSTAT->PeriodHighLimit_ = 0 ;
2135 pCHANSTAT->PlayingFineTune = 0 ;
2137 pCHANSTAT->PlayingVolume_ = 0 ;
2138 pCHANSTAT->FinalVolume_ = 0 ;
2139 pCHANSTAT->FinalVolume_L_ = 0 ;
2140 pCHANSTAT->FinalVolume_R_ = 0 ;
2141 pCHANSTAT->VolumeSlide = 0 ;
2142 pCHANSTAT->FineVolumeSlide = 0 ;
2143 pCHANSTAT->VolumeScale_ = ONE ;
2145 if( pMOD->FormatType == TYPE_MOD ){
2146 static const S32 DefaultPanning[4] = { 0x00 , 0xFF , 0xFF , 0x00 };
2147 pCHANSTAT->PlayingPanning_ = DefaultPanning[ i & 3 ] << SFT ;
2148 pCHANSTAT->FinalPanning_ = DefaultPanning[ i & 3 ] << SFT ;
2150 pCHANSTAT->PlayingPanning_ = 0x80 << SFT ;
2151 pCHANSTAT->FinalPanning_ = 0x80 << SFT ;
2153 pCHANSTAT->PanningSlide = 0 ;
2155 pCHANSTAT->idxVolumeEnvelopeTable = 0 ;
2156 pCHANSTAT->idxPanningEnvelopeTable = 0 ;
2158 pCHANSTAT->VibratoType = 0 ;
2159 pCHANSTAT->VibratoPosition_ = 0 ;
2160 pCHANSTAT->VibratoRate = 0 ;
2161 pCHANSTAT->VibratoDepth = 0 ;
2163 pCHANSTAT->TremoloType = 0 ;
2164 pCHANSTAT->TremoloPosition_ = 0 ;
2165 pCHANSTAT->TremoloRate = 0 ;
2166 pCHANSTAT->TremoloDepth = 0 ;
2168 pCHANSTAT->PortamentoInc = 0 ;
2169 pCHANSTAT->TonePortamentoInc = 0 ;
2170 pCHANSTAT->TonePortamentoDst_ = 0 ;
2171 pCHANSTAT->FinePortamentoInc = 0 ;
2172 pCHANSTAT->ExtraFinePortamentoInc = 0 ;
2174 pCHANSTAT->ArpeggioPeriod_[0] = 0 ;
2175 pCHANSTAT->ArpeggioPeriod_[1] = 0 ;
2176 pCHANSTAT->idxArpeggio = 0 ;
2178 pCHANSTAT->TremorCount = 0 ;
2179 pCHANSTAT->TremorOnTime = 0 ;
2180 pCHANSTAT->TremorOffTime = 0 ;
2181 pCHANSTAT->bTremorMute = FALSE ;
2183 pCHANSTAT->MultiRetrigCount = 0 ;
2184 pCHANSTAT->MultiRetrigInterval = 1 ;
2185 pCHANSTAT->MultiRetrigVolumeChange = 1 ;
2187 pCHANSTAT->PanbrelloType = 0 ;
2188 pCHANSTAT->PanbrelloPosition = 0 ;
2189 pCHANSTAT->PanbrelloRate = 0 ;
2190 pCHANSTAT->PanbrelloDepth = 0 ;
2192 pCHANSTAT->bFadeOut = FALSE ;
2193 pCHANSTAT->FadeOutVolume_1_15_16 = 1 << 16 ;
2195 pCHANSTAT->AutoVibratoPosition = 0 ;
2196 pCHANSTAT->AutoVibratoDepth_ = 0 ;
2198 pCHANSTAT->bSurround = FALSE ;
2200 pCHANSTAT->SamplePosition_ = 0 ;
2201 pCHANSTAT->SampleRate_ = 0 ;
2202 pCHANSTAT->SampleOffset = 0 ;
2203 pCHANSTAT->SampleHighOffset = 0 ;
2204 pCHANSTAT->bGrissando = FALSE ;
2205 pCHANSTAT->VolumeColumnContinueValue= 0 ;
2207 pCHANSTAT->pLastPlayingXM_SAMPLE = NULL ;
2208 pCHANSTAT->LastSamplePosition_ = 0 ;
2209 pCHANSTAT->LastWaveVal_L = 0 ;
2210 pCHANSTAT->LastWaveVal_R = 0 ;
2211 pCHANSTAT->LastSampleVolume_L_ = 0 ;
2212 pCHANSTAT->LastSampleVolume_R_ = 0 ;
2215 MOD__InitPatternLoop( pMOD );
2222 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2223 ▼ 波形データの出力 16bit stereo
2225 波形のミキシングを行っている。最適化するならここを重点的に。
2229 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
2230 static S32 MOD__OutPut_16BitStereo(
2232 ,U32 *pWaveOutPut /* 波形出力先(L R をひとまとめにして、U32 単位で出力する)*/
2233 ,S32 nWaveOutPut /* 出力波形数 */
2235 #define N_MIX ( 256 )
2237 S32 aMixBuff[ N_MIX * 2 ]; /* ミキシング用テンポラリバッファ(L R 交互)*/
2242 || pWaveOutPut == NULL
2245 if( pMOD->FormatType == TYPE_NOTAVAILABLE ) return( FALSE );
2247 while( nWaveOutPut > 0 ){
2248 S32 nWaveOutPutSub ;
2252 if( nWaveOutPut >= N_MIX ){
2253 nWaveOutPutSub = N_MIX ;
2255 nWaveOutPutSub = nWaveOutPut ;
2257 nWaveOutPut -= nWaveOutPutSub ;
2261 for( i=0 ; i<pMOD->XmHeader.NumberOfChannels ; i++ ){
2262 CHANSTAT *pCHANSTAT = &(pMOD->aCHANSTAT[ i ]);
2265 S32 SampleVolume_L_ = (pCHANSTAT->FinalVolume_L_ >> 6) * pMOD->GainControlScale_ >> SFT ;
2266 S32 SampleVolume_R_ = (pCHANSTAT->FinalVolume_R_ >> 6) * pMOD->GainControlScale_ >> SFT ;
2273 if( pCHANSTAT->LastSamplePosition_ != pCHANSTAT->SamplePosition_
2274 || pCHANSTAT->pLastPlayingXM_SAMPLE != pCHANSTAT->pPlayingXM_SAMPLE
2275 || pCHANSTAT->LastSampleVolume_L_ != SampleVolume_L_
2276 || pCHANSTAT->LastSampleVolume_R_ != SampleVolume_R_
2278 XM_SAMPLE *pXM_SAMPLE = pCHANSTAT->pPlayingXM_SAMPLE ;
2282 if( pXM_SAMPLE != NULL ){
2283 U32 SamplePosition_ = pCHANSTAT->SamplePosition_ ;
2284 U32 SampleLength_ = pXM_SAMPLE->SampleLength << SFT ;
2285 if( SamplePosition_ < SampleLength_ ){
2290 if( (pXM_SAMPLE->VoiceMode & VM_16BIT) == 0 ){
2291 S8 *pSampleData = reinterpret_cast<S8*>(pXM_SAMPLE->pSampleData) ;
2292 if( pSampleData != NULL ){
2293 Val0 = (S32)pSampleData[ SamplePosition_ >> SFT ] << 8 ;
2294 Val1 = (S32)pSampleData[ (SamplePosition_ >> SFT) + 1 ] << 8 ;
2297 S16 *pSampleData = reinterpret_cast<S16*>(pXM_SAMPLE->pSampleData);
2298 if( pSampleData != NULL ){
2299 Val0 = (S32)pSampleData[ SamplePosition_ >> SFT ];
2300 Val1 = (S32)pSampleData[ (SamplePosition_ >> SFT) + 1 ];
2304 Val = Val0 + (((Val1 - Val0) * ((S32)SamplePosition_ & DECIMAL)) >> SFT) ;
2305 NowVal_L = Val * SampleVolume_L_ >> SFT ;
2306 NowVal_R = Val * SampleVolume_R_ >> SFT ;
2310 pMOD->AntiNoiseVal_L += pCHANSTAT->LastWaveVal_L - NowVal_L ;
2311 pMOD->AntiNoiseVal_R += pCHANSTAT->LastWaveVal_R - NowVal_R ;
2316 /* プチノイズ対策しつつ、バッファをクリア */
2318 S32 AntiNoiseVal_L = pMOD->AntiNoiseVal_L ;
2319 S32 AntiNoiseVal_R = pMOD->AntiNoiseVal_R ;
2321 for( i=0 ; i<nWaveOutPutSub*2 ; i+=2 ){
2322 aMixBuff[i ] = AntiNoiseVal_L ;
2323 aMixBuff[i+1] = AntiNoiseVal_R ;
2324 AntiNoiseVal_L -= AntiNoiseVal_L >> 6 ;
2325 AntiNoiseVal_R -= AntiNoiseVal_R >> 6 ;
2328 pMOD->AntiNoiseVal_L = AntiNoiseVal_L ;
2329 pMOD->AntiNoiseVal_R = AntiNoiseVal_R ;
2334 for( i=0 ; i<pMOD->XmHeader.NumberOfChannels ; i++ ){
2335 CHANSTAT *pCHANSTAT = &(pMOD->aCHANSTAT[ i ]);
2336 XM_SAMPLE *pXM_SAMPLE = pCHANSTAT->pPlayingXM_SAMPLE ;
2339 S32 SampleVolume_L_ = (pCHANSTAT->FinalVolume_L_ >> 6) * pMOD->GainControlScale_ >> SFT ;
2340 S32 SampleVolume_R_ = (pCHANSTAT->FinalVolume_R_ >> 6) * pMOD->GainControlScale_ >> SFT ;
2347 /* 音量が 0 の時のための場合分け(計算誤差を考慮して判定を甘くしてある)*/
2348 if( SampleVolume_L_ < -ONE/128 || ONE/128 < SampleVolume_L_ ) CaseVal |= 1 ;
2349 if( SampleVolume_R_ < -ONE/128 || ONE/128 < SampleVolume_R_ ) CaseVal |= 2 ;
2351 if( pXM_SAMPLE != NULL ){
2352 S32 *pMixBuff = &(aMixBuff[ 0 ]) ;
2353 S32 *pMixEnd = &(aMixBuff[ nWaveOutPutSub * 2 ]) ;
2354 U32 SampleRate_ = pCHANSTAT->SampleRate_ ;
2355 U32 SamplePosition_ = pCHANSTAT->SamplePosition_ ;
2356 U32 SampleLength_ = pXM_SAMPLE->SampleLength << SFT ;
2357 U32 SampleLoopLength_ = pXM_SAMPLE->SampleLoopLength << SFT ;
2360 if( pXM_SAMPLE->pSampleData != NULL
2361 && pXM_SAMPLE->VoiceMode & VM_ON
2364 S32 bLoop = ((pXM_SAMPLE->VoiceMode & VM_LOOP) != 0) ;
2366 /*-------- マクロの定義(ここから)--------*/
2369 #define MACRO( _CaseVal_ , _nShift_ ) \
2370 while( pMixBuff < pMixEnd ){ \
2371 if( SamplePosition_ >= SampleLength_ ){ \
2372 if( bLoop == FALSE ) break ; \
2374 SamplePosition_ -= SampleLoopLength_ ; \
2375 } while( SamplePosition_ >= SampleLength_ ); \
2378 if( _CaseVal_ & 3 ){ \
2379 S32 Val0 , Val1 , Val ; \
2380 Val0 = (S32)pSampleData[ SamplePosition_ >> SFT ]; \
2381 if( _nShift_ ) Val0 <<= _nShift_ ; \
2382 Val1 = (S32)pSampleData[ (SamplePosition_ >> SFT) + 1 ]; \
2383 if( _nShift_ ) Val1 <<= _nShift_ ; \
2384 Val = Val0 + (((Val1 - Val0) * ((S32)SamplePosition_ & DECIMAL)) >> SFT) ; \
2385 if( _CaseVal_ & 1 ) Val_L = Val * SampleVolume_L_ >> SFT ; \
2386 if( _CaseVal_ & 2 ) Val_R = Val * SampleVolume_R_ >> SFT ; \
2387 if( _CaseVal_ & 1 ) pMixBuff[0] += Val_L ; \
2388 if( _CaseVal_ & 2 ) pMixBuff[1] += Val_R ; \
2391 SamplePosition_ += SampleRate_ ; \
2394 /*-------- マクロの定義(ここまで)--------*/
2396 if( (pXM_SAMPLE->VoiceMode & VM_16BIT) == 0 ){
2398 S8 *pSampleData = (S8*)pXM_SAMPLE->pSampleData ;
2422 S16 *pSampleData = (S16*)pXM_SAMPLE->pSampleData ;
2446 pCHANSTAT->SamplePosition_ = SamplePosition_ ;
2451 pCHANSTAT->pLastPlayingXM_SAMPLE = pCHANSTAT->pPlayingXM_SAMPLE ;
2452 pCHANSTAT->LastSamplePosition_ = pCHANSTAT->SamplePosition_ ;
2453 pCHANSTAT->LastWaveVal_L = Val_L ;
2454 pCHANSTAT->LastWaveVal_R = Val_R ;
2455 pCHANSTAT->LastSampleVolume_L_ = SampleVolume_L_ ;
2456 pCHANSTAT->LastSampleVolume_R_ = SampleVolume_R_ ;
2462 S32 *pMixBuff = &(aMixBuff[0]) ;
2465 while( nWaveOutPutSub > 0 ){
2466 S32 ValL = pMixBuff[0] ;
2467 S32 ValR = pMixBuff[1] ;
2470 if( ValL < -0x7FFF ){ ValL = -0x7FFF ; nOver++ ; }
2471 if( ValL > 0x7FFF ){ ValL = 0x7FFF ; nOver++ ; }
2472 if( ValR < -0x7FFF ){ ValR = -0x7FFF ; nOver++ ; }
2473 if( ValR > 0x7FFF ){ ValR = 0x7FFF ; nOver++ ; }
2475 *pWaveOutPut = (U32)((ValL & 0xFFFF) | (ValR << 16)) ;
2482 if( pMOD->bAutoGainControl ){
2484 pMOD->GainControlScale_ -= pMOD->GainControlScale_ >> 8 ;
2486 pMOD->GainControlScale_ += pMOD->GainControlScale_ >> 8 ;
2487 pMOD->GainControlScale_++ ;
2488 if( pMOD->GainControlScale_ > ONE ){
2489 pMOD->GainControlScale_ = ONE ;
2493 pMOD->GainControlScale_ = ONE ;
2504 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2507 指定数の 16bit stereo 波形を生成する。
2511 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
2513 MOD *pMOD /* this ポインター */
2514 ,U32 *pWaveOutPut /* 波形出力先(L R をひとまとめにして、U32 単位で出力する)*/
2515 ,S32 nWaveOutPut /* 出力波形数 */
2517 if( pMOD == NULL ) return( FALSE );
2518 if( pMOD->FormatType == TYPE_NOTAVAILABLE ) return( FALSE );
2524 if( pMOD->nRestWave > 0 ){
2525 if( pMOD->nRestWave >= nWaveOutPut ){
2526 /* 残存波形の出力のみで今回のノルマは達成される。*/
2527 MOD__OutPut_16BitStereo(
2533 pMOD->nRestWave -= nWaveOutPut ;
2535 pWaveOutPut += nWaveOutPut ;
2536 nWaveOutPut -= nWaveOutPut ;
2541 /* 残存波形が足りないぞ! 出せる分だけ出す。*/
2542 MOD__OutPut_16BitStereo(
2548 pWaveOutPut += pMOD->nRestWave ;
2549 nWaveOutPut -= pMOD->nRestWave ;
2551 pMOD->nRestWave = 0 ;
2557 /* 以下、1 tick 分の波形生成 */
2562 if( pMOD->bDone == TRUE ){
2564 if( pMOD->bLoopMode == FALSE ){
2566 MOD__InitPlay( pMOD );
2569 pMOD->nRestWave += pMOD->nWavePerTick ;
2574 pMOD->idxSequenceData = pMOD->XmHeader.RestartPosition ;
2575 if( pMOD->idxSequenceData >= pMOD->XmHeader.SongLength ){ /* 範囲オーバー? */
2576 pMOD->idxSequenceData = 0 ;
2580 ループ再生が有効なデータでは、ここで特に初期化手続きは取らない。
2581 しかし、ループ再生が有効かどうかを判断する手段が無い。
2582 やむを得ず、先頭から再生の場合は、ループ再生が無効と判断する。
2583 ModPlug でも同じ手法を用いているらしい。
2585 if( pMOD->idxSequenceData == 0 ){
2586 MOD__InitPlay( pMOD );
2589 pMOD->bDone = FALSE ;
2594 while( TRUE ){ /* ラベルジャンプ回避用 */
2596 S32 ModifyVal_ = ONE * (pMOD->nTickPerRow - 1) / pMOD->nTickPerRow ;
2597 S32 idxPattern = pMOD->XmHeader.aPatternOrderTable[ pMOD->idxSequenceData ];
2598 XM_PATTERN *pXM_PATTERN = pMOD->apXM_PATTERN[ idxPattern ];
2601 if( pXM_PATTERN == NULL ){
2602 #if (WARNING_LEVEL >= 2)
2603 LogMsg(pMOD->Instance,
2604 "MOD__PlaySong : 警告 \n"
2605 " pMOD->apXM_PATTERN[ %d ] == NULL です。\n"
2612 pPatternData = pXM_PATTERN->pPatternData ;
2613 if( pPatternData == NULL ){
2614 #if (WARNING_LEVEL >= 2)
2615 LogMsg(pMOD->Instance,
2616 "MOD__PlaySong : 警告 \n"
2617 " pMOD->apXM_PATTERN[ %d ]->pPatternData == NULL です。\n"
2624 #if (WARNING_LEVEL >= 2)
2625 if( pMOD->TickCount == 0
2628 LogMsg(pMOD->Instance,
2629 "Pos[%02d] Pat[%02d] ----------------------------------- \n"
2630 ,pMOD->idxSequenceData
2636 #if (WARNING_LEVEL >= 3)
2637 if( pMOD->TickCount == 0 ){
2638 LogMsg(pMOD->Instance,
2639 "Pos[%02d] Pat[%02d] ROW[%02d] "
2640 ,pMOD->idxSequenceData
2649 for( i=0 ; i < pMOD->XmHeader.NumberOfChannels ; i++ ){
2650 CHANSTAT *pCHANSTAT = &(pMOD->aCHANSTAT[i]) ;
2651 U8 *pNote = &pPatternData[ (pMOD->XmHeader.NumberOfChannels * pMOD->Row + i) * 5 ];
2652 S32 idxNowPatternNote ;
2653 S32 idxNowRealNote ;
2655 S32 NowVolumeColumn ;
2659 S32 bArpeggio = FALSE ; /* Arpeggio は有効か?(TRUE / FALSE)*/
2660 S32 bVibrato = FALSE ; /* Vibrato は有効か?(TRUE / FALSE)*/
2661 S32 bTremolo = FALSE ; /* Tremolo は有効か?(TRUE / FALSE)*/
2662 S32 bPanbrello = FALSE ; /* Panbrello は有効か?(TRUE / FALSE)*/
2663 S32 bNoteDelay = FALSE ; /* NoteDelay の最中か?(TRUE / FALSE)*/
2664 S32 bFirstTrigger = FALSE ; /* 初回トリガー? */
2667 #if (WARNING_LEVEL >= 3)
2668 if( pMOD->TickCount == 0 ){
2670 LogMsg( pMOD->Instance,":k%02X " , pNote[0] );
2672 LogMsg( pMOD->Instance,":--- " );
2676 LogMsg( pMOD->Instance,"@%02X " , pNote[1] );
2678 LogMsg( pMOD->Instance,"--- " );
2682 LogMsg(pMOD->Instance, "v%02X " , pNote[2] );
2684 LogMsg(pMOD->Instance, "--- " );
2688 LogMsg( pMOD->Instance,"e[%02X%02X]" , pNote[3] , pNote[4] );
2690 LogMsg(pMOD->Instance, "-------" );
2695 /* 現在行のステータス 解釈 & 内部変数の更新 */
2697 S32 idxPatternNote = ((S32)pNote[0]) - 1 ; /* 0..95 (0 = C-0, 95 = B-7) */
2698 S32 idxInst = ((S32)pNote[1]) - 1 ; /* Instrument (0-128) */
2699 S32 VolumeColumn = ((S32)pNote[2]) ; /* Volume column byte */
2700 S32 Command = ((S32)pNote[3]) << 4 ; /* Effect type */
2701 S32 Param = ((S32)pNote[4]) ; /* Effect parameter */
2702 S32 idxRealNote = -1 ;
2705 /* 拡張コマンド時、Param 上位 4 bit はコマンド番号になる */
2706 if( Command == 0x0E0
2709 Command |= Param >> 4 ;
2714 NoteDelay の解釈 & 初回トリガー。
2715 コマンド 0xED は、Param ==0 でも continue としない(MOD XM 共通)。
2716 Delay 中は、エフェクトも停止する。
2717 内部パラメーターの更新は、Delay が解除されたタイミングで行う。
2718 よって、Delay 時間が TickPerRow を超える時、内部パラメーターの
2722 if( Command == 0xED ){
2723 if( pMOD->TickCount < Param ){
2726 if( pMOD->TickCount == Param ) bFirstTrigger = TRUE ;
2728 if( pMOD->TickCount == 0 ) bFirstTrigger = TRUE ;
2732 if( bFirstTrigger ){
2733 S32 bPlay = FALSE ; /* 発声? */
2736 if( idxInst >= pMOD->XmHeader.NumberOfInstruments ) idxInst = -1 ;
2737 if( idxPatternNote > 96 ) idxPatternNote = -1 ;
2740 音階 音色 NoteOff の解釈の部分は、トラッカー毎の処理フローに
2741 依存する固体差の温床となっている。この固体差を再現するには、
2742 トラッカーの処理フローを予想して真似る必要があるが、
2743 ばかばかしいので、以下、すべてのケースを場合分けして対処する。
2746 /* CASE 1 : NoteOff & 音色有効 */
2747 if( idxPatternNote == 96
2750 pCHANSTAT->pPendingXM_INSTRUMENT = pMOD->apXM_INSTRUMENT[ idxInst ];
2754 if( idxPatternNote != -1
2755 && idxPatternNote != 96 /* NoteOff ではない */
2759 Tone-Portamento 時はトリガーは無い。
2760 Tone-Portamento 時でも、新規音色の指定がある時はトリガー。
2763 if( !( Command == 0x30 /* Tone-Portamento */
2764 || Command == 0x50 /* Tone-Portamento + Volume Slide */
2765 || (VolumeColumn & 0xF0) == 0xF0 /* Tone-Portamento */
2771 if( idxInst != -1 ){
2772 pCHANSTAT->bFadeOut = FALSE ;
2773 pCHANSTAT->pPendingXM_INSTRUMENT = pMOD->apXM_INSTRUMENT[ idxInst ];
2774 pCHANSTAT->idxVolumeEnvelopeTable = 0 ;
2775 pCHANSTAT->idxPanningEnvelopeTable = 0 ;
2776 pCHANSTAT->AutoVibratoPosition = 0 ;
2777 pCHANSTAT->AutoVibratoDepth_ = 0 ;
2778 pCHANSTAT->MultiRetrigCount = 0 ;
2779 if( pCHANSTAT->pPlayingXM_INSTRUMENT != pCHANSTAT->pPendingXM_INSTRUMENT ) bPlay = TRUE ;
2781 pCHANSTAT->pPlayingXM_INSTRUMENT = pCHANSTAT->pPendingXM_INSTRUMENT ;
2783 if( pCHANSTAT->pPlayingXM_INSTRUMENT != NULL ){
2784 pCHANSTAT->pPlayingXM_SAMPLE
2785 = pCHANSTAT->pPlayingXM_INSTRUMENT->apAllNoteXM_SAMPLE[ idxPatternNote ];
2788 if( pCHANSTAT->pPlayingXM_SAMPLE != NULL ){
2789 if( idxInst != -1 ){
2790 pCHANSTAT->PlayingVolume_ = pCHANSTAT->pPlayingXM_SAMPLE->Volume << SFT ;
2791 if( pMOD->FormatType == TYPE_XM ){
2792 pCHANSTAT->PlayingPanning_ = pCHANSTAT->pPlayingXM_SAMPLE->Panning << SFT ;
2795 pCHANSTAT->PlayingFineTune = pCHANSTAT->pPlayingXM_SAMPLE->FineTune ;
2796 idxRealNote = idxPatternNote + pCHANSTAT->pPlayingXM_SAMPLE->RelativeNoteNumber ;
2798 = pCHANSTAT->PendingPeriod_
2799 = MOD__KeyToPeriod_( pMOD , idxRealNote , pCHANSTAT->PlayingFineTune );
2801 /* Tone-Portamento 目標値は、どのようなコマンドの最中でも更新される */
2802 pCHANSTAT->TonePortamentoDst_ = Period_ ;
2806 pCHANSTAT->idxLastRealNote = idxRealNote ;
2807 pCHANSTAT->SamplePosition_ = 0 ;
2808 pCHANSTAT->PlayingPeriod_ = Period_ ;
2809 pCHANSTAT->PeriodLowLimit_ = MOD__KeyToPeriod_( pMOD , 12*10 - 1 , 0 );
2810 pCHANSTAT->PeriodHighLimit_ = MOD__KeyToPeriod_( pMOD , 0 , 0 );
2811 if( (pCHANSTAT->VibratoType & 4) == 0 ) pCHANSTAT->VibratoPosition_ = 0 ;
2812 if( (pCHANSTAT->TremoloType & 4) == 0 ) pCHANSTAT->TremoloPosition_ = 0 ;
2816 pCHANSTAT->PlayingVolume_ = 0 ;
2819 /* CASE 3 : 音階無効 & NoteOff でもない & 音色有効 */
2821 if( idxPatternNote == -1 /* 音階無効 */
2822 && idxPatternNote != 96 /* NoteOff ではない */
2823 && idxInst != -1 /* 音色有効 */
2825 pCHANSTAT->bFadeOut = FALSE ;
2826 pCHANSTAT->pPendingXM_INSTRUMENT = pMOD->apXM_INSTRUMENT[ idxInst ];
2828 if( pCHANSTAT->pPlayingXM_SAMPLE != NULL ){
2829 pCHANSTAT->PlayingVolume_ = pCHANSTAT->pPlayingXM_SAMPLE->Volume << SFT ;
2830 if( pMOD->FormatType == TYPE_XM ){
2831 pCHANSTAT->PlayingPanning_ = pCHANSTAT->pPlayingXM_SAMPLE->Panning << SFT ;
2835 pCHANSTAT->idxVolumeEnvelopeTable = 0 ;
2836 pCHANSTAT->idxPanningEnvelopeTable = 0 ;
2837 pCHANSTAT->AutoVibratoPosition = 0 ;
2838 pCHANSTAT->AutoVibratoDepth_ = 0 ;
2839 pCHANSTAT->MultiRetrigCount = 0 ;
2843 if( idxPatternNote == 96 ) pCHANSTAT->bFadeOut = TRUE ;
2846 pCHANSTAT->idxNowPatternNote = idxPatternNote ;
2847 pCHANSTAT->idxNowRealNote = idxRealNote ;
2848 pCHANSTAT->idxNowInst = idxInst ;
2849 pCHANSTAT->NowVolumeColumn = VolumeColumn ;
2850 pCHANSTAT->NowCommand = Command ;
2851 pCHANSTAT->NowParam = Param ;
2852 pCHANSTAT->NowPeriod_ = Period_ ;
2854 #if (WARNING_LEVEL >= 3)
2855 /* 発声があったなら、! を表示 */
2857 // LogMsg( "![%04X][%s]" , Period_ >> SFT , pCHANSTAT->pPlayingXM_SAMPLE->aszSampleName );
2858 LogMsg(pMOD->Instance, "!" );
2860 LogMsg(pMOD->Instance, " " );
2866 idxNowPatternNote = pCHANSTAT->idxNowPatternNote ;
2867 idxNowRealNote = pCHANSTAT->idxNowRealNote ;
2868 idxNowInst = pCHANSTAT->idxNowInst ;
2869 NowVolumeColumn = pCHANSTAT->NowVolumeColumn ;
2870 NowCommand = pCHANSTAT->NowCommand ;
2871 NowParam = pCHANSTAT->NowParam ;
2872 NowPeriod_ = pCHANSTAT->NowPeriod_ ;
2875 /* VolumeColumn コマンドを処理する */
2876 if( bNoteDelay == FALSE ){
2878 ModPlugTracker 上で動作確認した範囲からでしかわからないが、
2879 VolumeColumn のパラメーター省略による continue はかなり特殊。
2881 コマンド 6x 7x 8x 9x ax bx dx ex で、共通の continue 値を持っている。
2882 しかも、この値はメジャーコマンドに上書きされるのであった。
2884 if( (NowVolumeColumn & 0xF0) == 0x60
2885 || (NowVolumeColumn & 0xF0) == 0x70
2886 || (NowVolumeColumn & 0xF0) == 0x80
2887 || (NowVolumeColumn & 0xF0) == 0x90
2888 || (NowVolumeColumn & 0xF0) == 0xA0
2889 || (NowVolumeColumn & 0xF0) == 0xB0
2890 || (NowVolumeColumn & 0xF0) == 0xD0
2891 || (NowVolumeColumn & 0xF0) == 0xE0
2893 if( (NowVolumeColumn & 0xF) == 0 ){
2894 NowVolumeColumn = (NowVolumeColumn & 0xF0) | pCHANSTAT->VolumeColumnContinueValue ;
2896 pCHANSTAT->VolumeColumnContinueValue = NowVolumeColumn & 0xF ;
2900 switch( NowVolumeColumn & 0xF0 ){
2910 if( bFirstTrigger ){
2913 voleffect = 0x1* -> notevol = 0
2914 voleffect = 0x2* -> notevol = 0x10
2915 voleffect = 0x3* -> notevol = 0x20
2916 voleffect = 0x4* -> notevol = 0x30
2917 voleffect = 0x5* -> notevol = 0x40
2920 pCHANSTAT->PlayingVolume_ = (NowVolumeColumn - 0x10) << SFT ;
2924 /* $60-$6f : Volume slide down */
2925 /* $70-$7f : Volume slide up */
2927 コマンド Axy 5xy 6xy との併用で作用は加算される。
2931 if( bFirstTrigger ){
2932 if( (NowVolumeColumn & 0xF0) == 0x60 ){
2933 pCHANSTAT->VolumeSlide = -(NowVolumeColumn & 0x0F) ;
2935 if( (NowVolumeColumn & 0xF0) == 0x70 ){
2936 pCHANSTAT->VolumeSlide = (NowVolumeColumn & 0x0F) ;
2939 pCHANSTAT->PlayingVolume_ += pCHANSTAT->VolumeSlide * ModifyVal_ ;
2942 /* $80-$8f : Fine volume slide down */
2943 /* $90-$9f : Fine volume slide up */
2945 コマンド EAx EBx との併用で作用は加算される。
2949 if( bFirstTrigger ){
2950 if( (NowVolumeColumn & 0xF0) == 0x80 ){
2951 pCHANSTAT->FineVolumeSlide = -(NowVolumeColumn & 0x0F) ;
2953 if( (NowVolumeColumn & 0xF0) == 0x90 ){
2954 pCHANSTAT->FineVolumeSlide = (NowVolumeColumn & 0x0F) ;
2956 pCHANSTAT->PlayingVolume_ += pCHANSTAT->FineVolumeSlide << SFT ;
2960 /* $a0-$af : Set vibrato speed */
2961 /* $b0-$bf : Vibrato depth */
2963 オリジナルの FT2 では、$Ax では、スピードだけを設定したようだ。
2964 しかし、ModPlug では、$Ax $Bx ともに、ビブラートが発効する。
2966 コマンド 4xy との併用で、作用の増強はない。
2971 if( bFirstTrigger ){
2972 if( (NowVolumeColumn & 0xF0) == 0xA0 ){
2973 pCHANSTAT->VibratoRate = NowVolumeColumn & 0xF ;
2975 if( (NowVolumeColumn & 0xF0) == 0xB0 ){
2976 pCHANSTAT->VibratoDepth = NowVolumeColumn & 0xF ;
2982 /* $c0-$cf : Set panning */
2984 if( bFirstTrigger ){
2985 pCHANSTAT->PlayingPanning_ = (NowVolumeColumn & 0xF) * ((0xFF << SFT) / 0xF) ;
2989 /* $d0-$df : Panning slide left */
2990 /* $e0-$ef : Panning slide right */
2992 コマンド Pxy との併用で作用は加算される。
2993 パラメーター変数も、内部で共通となっている。
2997 if( bFirstTrigger ){
2998 if( (NowVolumeColumn & 0xF0) == 0xD0 ){
2999 pCHANSTAT->PanningSlide = -((S32)NowVolumeColumn & 0x0F) * 4 ; /* 左へ */
3001 if( (NowVolumeColumn & 0xF0) == 0xE0 ){
3002 pCHANSTAT->PanningSlide = ((S32)NowVolumeColumn & 0x0F) * 4 ; /* 右へ */
3005 pCHANSTAT->PlayingPanning_ += pCHANSTAT->PanningSlide * ModifyVal_ ;
3008 /* $f0-$ff : Tone porta */
3010 メジャーエフェクトの記述をペーストした。
3011 パラメーターは、3xx コマンドの 16 倍の効果を持つ。
3012 メジャーエフェクトの 3xx と併用する時、効果が加算される。
3015 if( bFirstTrigger ){
3016 if( NowVolumeColumn & 0xF ){
3017 pCHANSTAT->TonePortamentoInc = (NowVolumeColumn & 0xF) * 64 ;
3021 if( pCHANSTAT->TonePortamentoDst_ > pCHANSTAT->PlayingPeriod_ ){
3022 if( (pCHANSTAT->PlayingPeriod_ += pCHANSTAT->TonePortamentoInc * ModifyVal_)
3023 > pCHANSTAT->TonePortamentoDst_
3025 pCHANSTAT->PlayingPeriod_ = pCHANSTAT->TonePortamentoDst_ ;
3028 if( pCHANSTAT->TonePortamentoDst_ < pCHANSTAT->PlayingPeriod_ ){
3029 if( (pCHANSTAT->PlayingPeriod_ -= pCHANSTAT->TonePortamentoInc * ModifyVal_)
3030 < pCHANSTAT->TonePortamentoDst_
3032 pCHANSTAT->PlayingPeriod_ = pCHANSTAT->TonePortamentoDst_ ;
3039 ここで一度、パラメーターの飽和処理が必要。
3040 メジャーコマンドの処理後にも、やはり飽和処理をするので
3041 2度手間だが、ModPlug の仕様である。
3043 if( pCHANSTAT->PlayingVolume_ < 0 ) pCHANSTAT->PlayingVolume_ = 0 ;
3044 if( pCHANSTAT->PlayingVolume_ > (0x40 << SFT) ) pCHANSTAT->PlayingVolume_ = 0x40 << SFT ;
3045 if( pCHANSTAT->PlayingPanning_ < 0 ) pCHANSTAT->PlayingPanning_ = 0 ;
3046 if( pCHANSTAT->PlayingPanning_ > (0xFF << SFT) ) pCHANSTAT->PlayingPanning_ = 0xFF << SFT ;
3051 if( bNoteDelay == FALSE ){
3054 if( NowCommand == 0x00 ){
3055 /* エフェクト無し(= 0x000)を Arpeggio と混同しない */
3057 if( bFirstTrigger ){
3058 S32 FineTune = pCHANSTAT->PlayingFineTune ;
3059 S32 idxLastRealNote = pCHANSTAT->idxLastRealNote ;
3061 pCHANSTAT->ArpeggioPeriod_[0]
3062 = MOD__KeyToPeriod_( pMOD , idxLastRealNote + (NowParam & 0x0F) , FineTune );
3063 pCHANSTAT->ArpeggioPeriod_[1]
3064 = MOD__KeyToPeriod_( pMOD , idxLastRealNote + ((NowParam & 0xF0) >> 4) , FineTune );
3065 pCHANSTAT->idxArpeggio = 0 ;
3072 if( NowCommand == 0x10 ){
3073 if( bFirstTrigger ){
3074 if( pMOD->FormatType == TYPE_MOD /* MOD 形式では NowParam == 0 でも continue としない */
3075 || ( pMOD->FormatType == TYPE_XM /* XM 形式では NowParam == 0 は continue */
3079 pCHANSTAT->PortamentoInc = NowParam * 4 ;
3083 pCHANSTAT->PlayingPeriod_ -= pCHANSTAT->PortamentoInc * ModifyVal_ ;
3086 /* Portamento Down */
3087 if( NowCommand == 0x20 ){
3088 if( bFirstTrigger ){
3089 if( pMOD->FormatType == TYPE_MOD /* MOD 形式では NowParam == 0 でも continue としない */
3090 || ( pMOD->FormatType == TYPE_XM /* XM 形式では NowParam == 0 は continue */
3094 pCHANSTAT->PortamentoInc = NowParam * 4 ;
3098 pCHANSTAT->PlayingPeriod_ += pCHANSTAT->PortamentoInc * ModifyVal_ ;
3101 /* Tone-Portamento */
3102 /* Tone-Portamento + Volume Slide( NowParam は Volume Slide に適用)*/
3103 if( NowCommand == 0x30
3104 || NowCommand == 0x50
3106 if( bFirstTrigger ){
3107 if( NowCommand != 0x50 ){ /* 0x50 の時、NowParam は Volume Slide に適用 */
3108 /* MOD/XM 形式共に、NowParam == 0 は continue */
3110 pCHANSTAT->TonePortamentoInc = NowParam * 4 ;
3115 if( pCHANSTAT->TonePortamentoDst_ > pCHANSTAT->PlayingPeriod_ ){
3116 if( (pCHANSTAT->PlayingPeriod_ += pCHANSTAT->TonePortamentoInc * ModifyVal_)
3117 > pCHANSTAT->TonePortamentoDst_
3119 pCHANSTAT->PlayingPeriod_ = pCHANSTAT->TonePortamentoDst_ ;
3122 if( pCHANSTAT->TonePortamentoDst_ < pCHANSTAT->PlayingPeriod_ ){
3123 if( (pCHANSTAT->PlayingPeriod_ -= pCHANSTAT->TonePortamentoInc * ModifyVal_)
3124 < pCHANSTAT->TonePortamentoDst_
3126 pCHANSTAT->PlayingPeriod_ = pCHANSTAT->TonePortamentoDst_ ;
3132 /* Vibrato + Volume Slide( NowParam は Volume Slide に適用)*/
3133 if( NowCommand == 0x40
3134 || NowCommand == 0x60
3136 if( bFirstTrigger ){
3137 if( NowCommand != 0x60 ){ /* 0x60 の時、NowParam は Volume Slide に適用 */
3138 /* MOD/XM 形式ともに、Depth Rate 個別に 0 なら continue とする */
3139 if( NowParam & 0x0F ){
3140 pCHANSTAT->VibratoDepth = NowParam & 0x0F ;
3142 if( NowParam & 0xF0 ){
3143 pCHANSTAT->VibratoRate = (NowParam & 0xF0) >> 4 ;
3150 /* Tone-Portamento + Volume Slide( NowParam は Volume Slide に適用)*/
3151 /* Vibrato + Volume Slide( NowParam は Volume Slide に適用)*/
3153 if( NowCommand == 0x50
3154 || NowCommand == 0x60
3155 || NowCommand == 0xA0
3157 if( bFirstTrigger ){
3158 if( pMOD->FormatType == TYPE_MOD /* MOD 形式では NowParam == 0 でも continue としない */
3159 || ( pMOD->FormatType == TYPE_XM /* XM 形式では NowParam == 0 は continue */
3163 /* NowParam 上位 4 bit を優先的に参照する。*/
3164 if( NowParam & 0xF0 ){
3165 pCHANSTAT->VolumeSlide = ((NowParam & 0xF0) >> 4) ;
3167 pCHANSTAT->VolumeSlide = -((S32)NowParam & 0x0F) ;
3171 pCHANSTAT->PlayingVolume_ += pCHANSTAT->VolumeSlide * ModifyVal_ ;
3175 if( NowCommand == 0x70 ){
3176 if( bFirstTrigger ){
3177 /* MOD/XM 形式ともに、Depth Rate 個別に、0 なら continue */
3178 if( NowParam & 0x0F ){
3179 pCHANSTAT->TremoloDepth = NowParam & 0x0F ;
3181 if( NowParam & 0xF0 ){
3182 pCHANSTAT->TremoloRate = (NowParam & 0xF0) >> 4 ;
3189 if( NowCommand == 0x80 ){
3190 if( bFirstTrigger ){
3191 pCHANSTAT->bSurround = FALSE ;
3194 XM/IT 形式では、値は、00 (左) から FF (右)です。
3195 MOD/S3M 形式では、値は、00 (左) から 80 (右)です。
3196 MOD/S3M 形式において、値 A4 が指定されると、サラウンドモード(中央)になります。
3198 if( pMOD->FormatType == TYPE_MOD
3199 || pMOD->FormatType == TYPE_S3M
3201 S32 zxc = NowParam ;
3202 if( zxc == 0xA4 ){ /* コマンド 8A4 */
3203 pCHANSTAT->PlayingPanning_ = (0xFF << SFT) / 2 ;
3204 pCHANSTAT->bSurround = TRUE ;
3207 pCHANSTAT->PlayingPanning_ = zxc * ((0xFF << SFT) / 0x80) ;
3211 if( pMOD->FormatType == TYPE_XM
3212 || pMOD->FormatType == TYPE_IT
3214 pCHANSTAT->PlayingPanning_ = NowParam << SFT ;
3219 /* Set Sample Offset */
3220 if( NowCommand == 0x90 ){
3224 XM_SAMPLE *pXM_SAMPLE = pCHANSTAT->pPlayingXM_SAMPLE ;
3225 U32 SamplePosition = 0 ;
3227 /* MOD/XM 形式ともに、Param == 0 なら continue */
3229 pCHANSTAT->SampleOffset = NowParam ;
3231 SamplePosition = pCHANSTAT->SampleOffset * 0x100 + pCHANSTAT->SampleHighOffset * 0x10000 ;
3235 MOD 形式の場合、サンプリング終点を超えるなら先頭に戻す。
3236 ループが有効なら、それを考慮した位置に再生点を置く。
3239 if( SamplePosition >= (U32)pXM_SAMPLE->SampleLength ){
3240 #if (WARNING_LEVEL >= 1)
3241 LogMsg(pMOD->Instance,
3243 "MOD__PlaySong : 警告 \n"
3244 " CH = %d : コマンド 9%02X にて、範囲オーバー検出。POS=[%X / %X] \n"
3248 ,pXM_SAMPLE->SampleLength
3251 if( pXM_SAMPLE->VoiceMode & VM_LOOP ){
3252 SamplePosition -= pXM_SAMPLE->SampleLoopStart ;
3253 SamplePosition %= pXM_SAMPLE->SampleLoopLength ;
3254 SamplePosition += pXM_SAMPLE->SampleLoopStart ;
3259 pCHANSTAT->SamplePosition_ = SamplePosition << SFT ;
3263 /* Position Jump(この行自体は演奏される)*/
3264 if( NowCommand == 0xB0 ){
3265 if( bFirstTrigger ){
3266 if( pMOD->bLoopMode == TRUE /* ループ再生時は無条件に許可 */
3267 || NowParam >= pMOD->idxSequenceData /* 前方のジャンプは無条件に許可 */
3269 pMOD->BreakSequence = NowParam ;
3275 if( NowCommand == 0xC0 ){
3276 if( bFirstTrigger ){
3277 pCHANSTAT->PlayingVolume_ = NowParam << SFT ;
3281 /* Pattern Break(この行自体は演奏される)*/
3282 if( NowCommand == 0xD0 ){
3283 if( bFirstTrigger ){
3284 pMOD->BreakRow = ((NowParam & 0xF0) >> 4) * 10 + (NowParam & 0x0F) ;
3285 pMOD->BreakSequence = pMOD->idxSequenceData + 1 ;
3289 /* Extended MOD Commands */
3290 if( (NowCommand & 0xFF0) == 0x0E0 ){
3291 switch( NowCommand ){
3292 /* E0x : Set Filter */
3296 #if (WARNING_LEVEL >= 1)
3297 LogMsg(pMOD->Instance,
3298 "MOD__PlaySong : 警告 \n"
3299 " 未対応のコマンド %03X です。\n"
3304 Amiga がハードウェアレベルで実装していた機能をコントロール
3310 /* E1x : Fine Portamento Up */
3311 /* E2x : Fine Portamento Down */
3314 if( bFirstTrigger ){
3315 if( pMOD->FormatType == TYPE_MOD /* MOD 形式では NowParam == 0 でも continue としない */
3316 || ( pMOD->FormatType == TYPE_XM /* XM 形式では NowParam == 0 は continue */
3320 pCHANSTAT->FinePortamentoInc = NowParam * 4 ;
3322 if( NowCommand == 0xE1 ){
3323 pCHANSTAT->PlayingPeriod_ -= pCHANSTAT->FinePortamentoInc << SFT ;
3325 if( NowCommand == 0xE2 ){
3326 pCHANSTAT->PlayingPeriod_ += pCHANSTAT->FinePortamentoInc << SFT ;
3331 /* E3x : Grissando Control */
3333 if( bFirstTrigger ){
3335 pCHANSTAT->bGrissando = TRUE ;
3337 pCHANSTAT->bGrissando = FALSE ;
3342 /* E4x : Vibrato waveform */
3344 if( bFirstTrigger ){
3345 pCHANSTAT->VibratoType = NowParam ;
3349 /* E5x : Set FineTune(MOD 形式のみサポート)*/
3352 && pMOD->FormatType == TYPE_MOD
3354 S32 Val = NowParam ;
3355 if( Val >= 8 ) Val = Val - 16 ;
3358 pCHANSTAT->PlayingFineTune = Val << 4 ;
3359 pCHANSTAT->PendingPeriod_
3360 = pCHANSTAT->PlayingPeriod_
3361 = MOD__KeyToPeriod_( pMOD , pCHANSTAT->idxLastRealNote , pCHANSTAT->PlayingFineTune );
3365 /* E6x : Pattern loop */
3367 if( bFirstTrigger ){
3370 重複設定が行われた場合、最新のものが有効
3372 if( NowParam == 0 ){
3373 /* 同一個所に復帰点を再設定する場合はキャンセル */
3374 if( pCHANSTAT->PatternLoopRow != pMOD->Row ){
3375 pCHANSTAT->PatternLoopRow = pMOD->Row ;
3376 pCHANSTAT->PatternLoopCount = 0 ;
3382 if( NowParam > pCHANSTAT->PatternLoopCount ){
3383 pCHANSTAT->PatternLoopCount++ ;
3384 pMOD->BreakRow = pCHANSTAT->PatternLoopRow ;
3390 /* E7x : Tremolo waveform */
3392 if( bFirstTrigger ){
3393 pCHANSTAT->TremoloType = NowParam ;
3397 /* E8x : Set Pannning */
3399 if( bFirstTrigger ){
3400 pCHANSTAT->PlayingPanning_ = NowParam * ((0xFF << SFT) / 0x0F) ;
3404 /* E9x : Retrigger note */
3406 この旧コマンドは、非常にややこしい仕様を持っている。
3407 tick 0 のトリガーは、通常の Note 欄の内容で処理。
3408 それ以降のトリガーはここで処理しなければならない。
3410 スパゲティー化必至。しかもこれで正しいという保証も無い。
3413 S32 zxc = NowParam ;
3414 if( zxc <= 0 ) zxc = 1 ;
3415 if( bFirstTrigger == FALSE
3416 && (pMOD->TickCount % zxc) == 0
3420 -> PendingInst = NowInst
3421 PlayingInst = NowInst
3422 PlayingPeriod = PendingPeriod
3423 PlayingInst.Sample リスタート
3424 Env 形状 = PlayingInst
3426 Auto-Vibrato は PlayingInst でリスタート
3428 -> PendingInst = PlayingInst (逆流。ひどいっす。)
3429 PlayingPeriod = PendingPeriod
3430 PlayingInst.Sample リスタート
3431 Env 形状 = PlayingInst
3433 Auto-Vibrato は PlayingInst でリスタート
3435 そもそも、PendingInst でなく NowInst を参照している点が不自然。
3436 古いデータの互換性のためなのか、ModPlug のバグなのか、それさえ不明。
3438 if( idxNowInst != -1 ){
3439 pCHANSTAT->pPlayingXM_INSTRUMENT = pCHANSTAT->pPendingXM_INSTRUMENT
3440 = pMOD->apXM_INSTRUMENT[ idxNowInst ];
3441 pCHANSTAT->PlayingPeriod_ = pCHANSTAT->PendingPeriod_ ;
3442 if( pCHANSTAT->pPlayingXM_INSTRUMENT != NULL ){
3443 pCHANSTAT->pPlayingXM_SAMPLE
3445 pPlayingXM_INSTRUMENT->
3446 apAllNoteXM_SAMPLE[ pCHANSTAT->idxLastRealNote ];
3449 pCHANSTAT->pPendingXM_INSTRUMENT = pCHANSTAT->pPlayingXM_INSTRUMENT ;
3450 pCHANSTAT->PlayingPeriod_ = pCHANSTAT->PendingPeriod_ ;
3452 pCHANSTAT->SamplePosition_ = 0 ;
3453 pCHANSTAT->idxVolumeEnvelopeTable = 0 ;
3454 pCHANSTAT->idxPanningEnvelopeTable = 0 ;
3455 pCHANSTAT->AutoVibratoPosition = 0 ;
3456 pCHANSTAT->AutoVibratoDepth_ = 0 ;
3460 /* EAx : Fine volslide up */
3461 /* EBx : Fine volslide down */
3464 if( bFirstTrigger ){
3465 if( pMOD->FormatType == TYPE_MOD /* MOD 形式では NowParam == 0 でも continue としない */
3466 || ( pMOD->FormatType == TYPE_XM /* XM 形式では NowParam == 0 は continue */
3470 pCHANSTAT->FineVolumeSlide = NowParam ;
3472 if( NowCommand == 0xEA ){
3473 pCHANSTAT->PlayingVolume_ += pCHANSTAT->FineVolumeSlide << SFT ;
3475 if( NowCommand == 0xEB ){
3476 pCHANSTAT->PlayingVolume_ -= pCHANSTAT->FineVolumeSlide << SFT ;
3483 if( pMOD->TickCount == NowParam ){
3484 pCHANSTAT->PlayingVolume_ = 0 ;
3495 if( bFirstTrigger ){
3496 pMOD->PatternDelay = NowParam ;
3500 /* Set active macro(XM形式のみサポート)*/
3503 #if (WARNING_LEVEL >= 1)
3504 LogMsg(pMOD->Instance,
3505 "MOD__PlaySong : 警告 \n"
3506 " 未対応のコマンド %03X です。\n"
3511 このコマンドが、どのような機能なのかは不明。
3512 MOD 形式の場合は、一部のトラッカーにて、サンプリング再生の方向を
3513 選択できたようだが、ModPlug にはそのような機能は存在しない。
3514 XM 形式の場合は、MIDI MACRO 関係の機能を持っているが、
3515 詳細不明。というか、使っているデータを見たことがない。
3521 /* Set Speed/Tempo (コマンド Fxx) */
3522 if( NowCommand == 0xF0 ){
3523 if( bFirstTrigger ){
3525 if(( NowParam <= 0x20 && pMOD->FormatType == TYPE_MOD)
3526 || (NowParam < 0x20 && pMOD->FormatType == TYPE_XM)
3528 pMOD->nTickPerRow = NowParam ;
3529 if( pMOD->nTickPerRow <= 0 ) pMOD->nTickPerRow = 1 ;
3531 pMOD->BPM = NowParam ;
3534 /* 省略時は、前回までの値を継続して使用 */
3539 /* Global volume(コマンド Gxx)*/
3540 if( NowCommand == 0x100 ){
3541 if( bFirstTrigger ){
3542 pMOD->GlobalVolume_ = NowParam << SFT ;
3546 /* Global volume slide(コマンド Hxy)*/
3547 if( NowCommand == 0x110 ){
3548 if( bFirstTrigger ){
3550 /* NowParam 上位 4 bit を優先的に参照する。*/
3551 if( NowParam & 0xF0 ){
3552 pMOD->GlobalVolumeSlide = ((NowParam & 0xF0) >> 4) ;
3554 pMOD->GlobalVolumeSlide = -((S32)NowParam & 0x0F) ;
3558 pMOD->GlobalVolume_ += pMOD->GlobalVolumeSlide * ModifyVal_ ;
3561 /* Keyoff(コマンド Kxx)*/
3563 パラメーター xx に意味はない、らしい。
3565 if( NowCommand == 0x140 ){
3566 if( bFirstTrigger ){
3567 pCHANSTAT->bFadeOut = TRUE ;
3571 /* Set envpos(コマンド Lxx)*/
3572 if( NowCommand == 0x150 ){
3573 if( bFirstTrigger ){
3574 pCHANSTAT->idxVolumeEnvelopeTable = NowParam ;
3575 pCHANSTAT->idxPanningEnvelopeTable = NowParam ;
3579 /* Panning slide(コマンド Pxy)*/
3580 if( NowCommand == 0x190 ){
3581 if( bFirstTrigger ){
3583 /* 例外的に、NowParam 下位 4 bit を優先的に参照する。*/
3584 if( NowParam & 0x0F ){
3585 pCHANSTAT->PanningSlide = -((S32)NowParam & 0x0F) * 4 ; /* 左へスライド */
3587 pCHANSTAT->PanningSlide = ((NowParam & 0xF0) >> 4) * 4 ; /* 右へスライド */
3591 pCHANSTAT->PlayingPanning_ += pCHANSTAT->PanningSlide * ModifyVal_ ;
3594 /* Multi retrig(コマンド Rxy)*/
3596 tick 0 から発効し、ModifyVal_ の補正は不要。
3597 古い世代の XM では、tick 0 では発効せず、ModifyVal_ の補正が必要らしい(未対応)。
3599 if( NowCommand == 0x1B0 ){
3600 /* +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F */
3601 static const S8 aMultiRetrigMulTable[] = { 0, 0, 0, 0, 0, 0, 10, 8, 0, 0, 0, 0, 0, 0, 24, 32 };
3602 static const S8 aMultiRetrigAddTable[] = { 0, -1, -2, -4, -8,-16, 0, 0, 0, +1, +2, +4, +8,+16, 0, 0 };
3604 if( bFirstTrigger ){
3605 /* x y 個別に、0 なら continue */
3606 if( NowParam & 0x0F ){
3607 pCHANSTAT->MultiRetrigInterval = NowParam & 0x0F ;
3609 if( NowParam & 0xF0 ){
3610 pCHANSTAT->MultiRetrigVolumeChange = (NowParam & 0xF0) >> 4 ;
3614 if( pCHANSTAT->MultiRetrigCount >= pCHANSTAT->MultiRetrigInterval
3615 && pCHANSTAT->MultiRetrigInterval
3617 pCHANSTAT->SamplePosition_ = 0 ; /* 再生位置の初期化のみ */
3618 pCHANSTAT->MultiRetrigCount = 0 ;
3620 if( aMultiRetrigMulTable[ pCHANSTAT->MultiRetrigVolumeChange ] == 0 ){
3621 pCHANSTAT->PlayingVolume_ += aMultiRetrigAddTable[ pCHANSTAT->MultiRetrigVolumeChange ] << SFT ;
3622 if( pCHANSTAT->PlayingVolume_ < ( 0 << SFT) ) pCHANSTAT->PlayingVolume_ = ( 0 << SFT) ;
3623 if( pCHANSTAT->PlayingVolume_ > (0x40 << SFT) ) pCHANSTAT->PlayingVolume_ = (0x40 << SFT) ;
3625 pCHANSTAT->PlayingVolume_
3626 = pCHANSTAT->PlayingVolume_ * aMultiRetrigMulTable[ pCHANSTAT->MultiRetrigVolumeChange ] >> 4 ;
3627 if( pCHANSTAT->PlayingVolume_ > (0x40 << SFT) ) pCHANSTAT->PlayingVolume_ = (0x40 << SFT) ;
3630 pCHANSTAT->MultiRetrigCount++ ;
3633 /* Tremor(コマンド Txy)*/
3635 このコマンドは、現在のチャンネルの発声を、指定 frame 単位で ON OFF する機能です。
3636 例えば、T[ontime][offtime] の様に記述します。
3637 x=ontime, y=offtime とすると、x frame の間ボリューム値は変化せず、
3638 その後 y frame の間ミュート状態(無音)になります。
3639 ontime / offtime の正確な持続時間は MOD / XM / S3M / IT の間で異なるので注意です。
3641 if( NowCommand == 0x1D0 ){
3642 pCHANSTAT->bTremorMute = FALSE ;
3644 if( bFirstTrigger ){
3645 /* x y 共に 0 の時のみ continue */
3647 pCHANSTAT->TremorOnTime = ((NowParam >> 4) & 0xF) + 1 ;
3648 pCHANSTAT->TremorOffTime = (NowParam & 0xF) + 1 ;
3650 pCHANSTAT->TremorCount = 0 ;
3654 TickPerRow = (TremorOnTime + TremorOffTime) * n + 1
3655 を満たさない場合、ModPlug では安定しない動作をする(バグ?)が、
3656 そこまでは再現できていない。かなり無意味っぽいので、妥協決定。
3659 if( pCHANSTAT->TremorCount >= pCHANSTAT->TremorOnTime ){
3660 pCHANSTAT->bTremorMute = TRUE ;
3663 pCHANSTAT->TremorCount++ ;
3664 if( pCHANSTAT->TremorCount >= pCHANSTAT->TremorOnTime + pCHANSTAT->TremorOffTime ){
3665 pCHANSTAT->TremorCount = 0 ;
3669 pCHANSTAT->bTremorMute = FALSE ;
3672 /* Extended XM Effects (コマンド Xxy) */
3673 if( (NowCommand & 0xFF0) == 0x210 ){
3674 switch( NowCommand ){
3675 /* X1x : Extra Fine Portamento Up */
3676 /* X2x : Extra Fine Portamento Down */
3679 if( bFirstTrigger ){
3681 pCHANSTAT->ExtraFinePortamentoInc = NowParam ;
3683 if( NowCommand == 0x211 ){
3684 pCHANSTAT->PlayingPeriod_ -= pCHANSTAT->ExtraFinePortamentoInc << SFT ;
3686 if( NowCommand == 0x212 ){
3687 pCHANSTAT->PlayingPeriod_ += pCHANSTAT->ExtraFinePortamentoInc << SFT ;
3692 /* X5x : Panbrello wave form */
3694 pCHANSTAT->PanbrelloType = NowParam ;
3697 /* X6x : Fine pattern delay */
3699 if( bFirstTrigger ){
3700 pMOD->FinePatternDelay = NowParam ;
3704 /* X9x : Surround control */
3707 /* X90 : Surround Off */
3709 pCHANSTAT->bSurround = FALSE ;
3712 /* X91 : Surround On */
3714 pCHANSTAT->PlayingPanning_ = (0xFF << SFT) / 2 ;
3715 pCHANSTAT->bSurround = TRUE ;
3718 /* X98 : Reverb Off */
3721 #if (WARNING_LEVEL >= 1)
3722 LogMsg(pMOD->Instance,
3723 "MOD__PlaySong : 警告 \n"
3724 " 未対応のコマンド %03X です。\n"
3730 /* X99 : Reverb On */
3733 #if (WARNING_LEVEL >= 1)
3734 LogMsg(pMOD->Instance,
3735 "MOD__PlaySong : 警告 \n"
3736 " 未対応のコマンド %03X です。\n"
3742 /* X9A : Center surround */
3745 #if (WARNING_LEVEL >= 1)
3746 LogMsg(pMOD->Instance,
3747 "MOD__PlaySong : 警告 \n"
3748 " 未対応のコマンド %03X です。\n"
3754 /* X9B : Quad surround */
3757 #if (WARNING_LEVEL >= 1)
3758 LogMsg(pMOD->Instance,
3759 "MOD__PlaySong : 警告 \n"
3760 " 未対応のコマンド %03X です。\n"
3766 /* X9C : Grobal filters */
3769 #if (WARNING_LEVEL >= 1)
3770 LogMsg(pMOD->Instance,
3771 "MOD__PlaySong : 警告 \n"
3772 " 未対応のコマンド %03X です。\n"
3778 /* X9D : Local filters */
3781 #if (WARNING_LEVEL >= 1)
3782 LogMsg(pMOD->Instance,
3783 "MOD__PlaySong : 警告 \n"
3784 " 未対応のコマンド %03X です。\n"
3790 /* X9E : Play Forward */
3793 #if (WARNING_LEVEL >= 1)
3794 LogMsg(pMOD->Instance,
3795 "MOD__PlaySong : 警告 \n"
3796 " 未対応のコマンド %03X です。\n"
3802 /* X9F : Play Backward */
3805 #if (WARNING_LEVEL >= 1)
3806 LogMsg(pMOD->Instance,
3807 "MOD__PlaySong : 警告 \n"
3808 " 未対応のコマンド %03X です。\n"
3816 /* XAx : Set high offset */
3818 pCHANSTAT->SampleHighOffset = NowParam ;
3823 /* Panbrello(コマンド Yxy)*/
3824 if( NowCommand == 0x220 ){
3825 if( bFirstTrigger ){
3826 /* Depth Rate 個別に、0 なら continue */
3827 if( NowParam & 0x0F ){
3828 pCHANSTAT->PanbrelloDepth = NowParam & 0x0F ;
3830 if( NowParam & 0xF0 ){
3831 pCHANSTAT->PanbrelloRate = (NowParam & 0xF0) >> 4 ;
3837 /* Midi macro(コマンド Zxy)*/
3838 if( NowCommand == 0x230 ){
3840 #if (WARNING_LEVEL >= 1)
3841 LogMsg(pMOD->Instance,
3842 "MOD__PlaySong : 警告 \n"
3843 " 未対応のコマンド %03X です。\n"
3853 if( pCHANSTAT->pPlayingXM_INSTRUMENT != NULL
3854 && pCHANSTAT->pPlayingXM_SAMPLE != NULL
3856 XM_INSTRUMENT *pXM_INSTRUMENT = pCHANSTAT->pPlayingXM_INSTRUMENT ;
3860 if( pCHANSTAT->PlayingPanning_ < 0 ) pCHANSTAT->PlayingPanning_ = 0 ;
3861 if( pCHANSTAT->PlayingPanning_ > (0xFF << SFT) ) pCHANSTAT->PlayingPanning_ = (0xFF << SFT) ;
3863 /* 0x000 ~ 0x0FF -> 0x000 ~ 0x100 */
3864 FinalPanning_ = pCHANSTAT->PlayingPanning_ * 0x100 / 0xFF ;
3868 ModfyVal_ の倍率は反映しないのが正しい。
3869 ちなみに、Panbrello 波形には、リスタートの概念が無いようだ。
3872 S32 Val = ( ( _aaWaveTable[
3873 _aPanbrelloWaveType[
3874 pCHANSTAT->PanbrelloType & 3
3877 ((pCHANSTAT->PanbrelloPosition + 0x10) >> 2) & 0x3F
3878 ] * pCHANSTAT->PanbrelloDepth
3881 pCHANSTAT->PanbrelloPosition += pCHANSTAT->PanbrelloRate ;
3883 FinalPanning_ += Val << SFT ;
3886 if( FinalPanning_ > (0x100 << SFT) ) FinalPanning_ = 0x100 << SFT ;
3887 if( FinalPanning_ < 0 ) FinalPanning_ = 0 ;
3891 if( pXM_INSTRUMENT->PanningType & ENV_ON ){
3892 if( pCHANSTAT->idxPanningEnvelopeTable > 324 ) pCHANSTAT->idxPanningEnvelopeTable = 324 ;
3895 S32 Val = pXM_INSTRUMENT->PanningEnvelopeTable[ pCHANSTAT->idxPanningEnvelopeTable ];
3896 if( FinalPanning_ >= (0x80 << SFT) ){
3897 FinalPanning_ += (Val - 32) * ((0x100 << SFT) - FinalPanning_) / 32 ;
3899 FinalPanning_ += (Val - 32) * FinalPanning_ / 32 ;
3904 if( FinalPanning_ > (0x100 << SFT) ) FinalPanning_ = 0x100 << SFT ;
3905 if( FinalPanning_ < 0 ) FinalPanning_ = 0 ;
3907 if( !( pXM_INSTRUMENT->PanningType & ENV_SUSTAIN
3908 && pCHANSTAT->bFadeOut == FALSE
3909 && pCHANSTAT->idxPanningEnvelopeTable == pXM_INSTRUMENT->PanningSustainPoint
3912 pCHANSTAT->idxPanningEnvelopeTable++ ;
3914 if( pXM_INSTRUMENT->PanningType & ENV_LOOP ){
3915 if( pCHANSTAT->idxPanningEnvelopeTable >= pXM_INSTRUMENT->PanningLoopEndPoint ){
3916 pCHANSTAT->idxPanningEnvelopeTable = pXM_INSTRUMENT->PanningLoopStartPoint ;
3922 if( FinalPanning_ > (0x100 << SFT) ) FinalPanning_ = 0x100 << SFT ;
3923 if( FinalPanning_ < 0 ) FinalPanning_ = 0 ;
3926 pCHANSTAT->FinalPanning_ = FinalPanning_ ;
3930 if( pCHANSTAT->pPlayingXM_INSTRUMENT != NULL
3931 && pCHANSTAT->pPlayingXM_SAMPLE != NULL
3933 XM_INSTRUMENT *pXM_INSTRUMENT = pCHANSTAT->pPlayingXM_INSTRUMENT ;
3937 if( pCHANSTAT->PlayingVolume_ > (0x40 << SFT) ) pCHANSTAT->PlayingVolume_ = 0x40 << SFT ;
3938 if( pCHANSTAT->PlayingVolume_ < 0 ) pCHANSTAT->PlayingVolume_ = 0 ;
3939 if( pMOD->GlobalVolume_ > (0x40 << SFT) ) pMOD->GlobalVolume_ = 0x40 << SFT ;
3940 if( pMOD->GlobalVolume_ < 0 ) pMOD->GlobalVolume_ = 0 ;
3942 FinalVolume_ = pCHANSTAT->PlayingVolume_ ;
3946 S32 Val = _aaWaveTable[
3947 _aTremoloWaveType[ pCHANSTAT->TremoloType & 3 ]
3949 (pCHANSTAT->TremoloPosition_ >> SFT) & 0x3F
3951 pCHANSTAT->TremoloPosition_ += pCHANSTAT->TremoloRate * ModifyVal_ ;
3953 /* MOD 形式では、最大振幅は -0x1F ~ +0x1F */
3954 if( pMOD->FormatType == TYPE_MOD ){
3955 FinalVolume_ += (Val << (SFT - 6)) * pCHANSTAT->TremoloDepth ;
3958 /* XM 形式では、最大振幅は -0x3F ~ +0x3F */
3959 if( pMOD->FormatType == TYPE_XM ){
3960 FinalVolume_ += (Val << (SFT - 5)) * pCHANSTAT->TremoloDepth ;
3964 if( FinalVolume_ > (0x40 << SFT) ) FinalVolume_ = 0x40 << SFT ;
3965 if( FinalVolume_ < 0 ) FinalVolume_ = 0 ;
3969 if( pCHANSTAT->bTremorMute ) FinalVolume_ = 0 ;
3971 /* キーオフ フェードアウト処理 */
3973 if( pCHANSTAT->bFadeOut == TRUE ){
3974 if( (pCHANSTAT->pPlayingXM_INSTRUMENT->VolumeType & ENV_ON) == 0 ){
3975 /* ボリュームエンベロープが無効の場合は、瞬時に音量 0 となる */
3976 pCHANSTAT->PlayingVolume_ = 0 ;
3978 pCHANSTAT->bFadeOut = FALSE ;
3980 /* ボリュームエンベロープが有効の場合はフェードアウト */
3981 pCHANSTAT->FadeOutVolume_1_15_16 -= (S32)pXM_INSTRUMENT->VolumeFadeout * 2 ;
3982 if( pCHANSTAT->FadeOutVolume_1_15_16 < 0 ) pCHANSTAT->FadeOutVolume_1_15_16 = 0 ;
3985 pCHANSTAT->FadeOutVolume_1_15_16 = 1 << 16 ;
3987 FinalVolume_ = (FinalVolume_ * (pCHANSTAT->FadeOutVolume_1_15_16 >> 8)) >> 8 ;
3991 if( pXM_INSTRUMENT->VolumeType & ENV_ON ){
3992 if( pCHANSTAT->idxVolumeEnvelopeTable > 324 ) pCHANSTAT->idxVolumeEnvelopeTable = 324 ;
3993 FinalVolume_ = ( FinalVolume_
3994 * pXM_INSTRUMENT->VolumeEnvelopeTable[ pCHANSTAT->idxVolumeEnvelopeTable ]
3997 if( !( pXM_INSTRUMENT->VolumeType & ENV_SUSTAIN
3998 && pCHANSTAT->bFadeOut == FALSE
3999 && pCHANSTAT->idxVolumeEnvelopeTable == pXM_INSTRUMENT->VolumeSustainPoint
4002 pCHANSTAT->idxVolumeEnvelopeTable++ ;
4004 if( pXM_INSTRUMENT->VolumeType & ENV_LOOP ){
4005 if( pCHANSTAT->idxVolumeEnvelopeTable >= pXM_INSTRUMENT->VolumeLoopEndPoint ){
4006 pCHANSTAT->idxVolumeEnvelopeTable = pXM_INSTRUMENT->VolumeLoopStartPoint ;
4012 if( FinalVolume_ > (0x40 << SFT) ) FinalVolume_ = 0x40 << SFT ;
4013 if( FinalVolume_ < 0 ) FinalVolume_ = 0 ;
4017 FinalVolume_ = (FinalVolume_ >> 6) * (pMOD->GlobalVolume_ >> 6) >> (SFT - 6) ;
4020 FinalVolume_ = (FinalVolume_ >> 6) * pCHANSTAT->VolumeScale_ >> (SFT - 6) ;
4021 FinalVolume_ = (FinalVolume_ >> 6) * pMOD->GlobalVolumeScale_ >> (SFT - 6) ;
4024 pCHANSTAT->FinalVolume_ = FinalVolume_ ;
4025 pCHANSTAT->FinalVolume_R_ = FinalVolume_ * (pCHANSTAT->FinalPanning_ >> SFT) >> 8 ;
4026 pCHANSTAT->FinalVolume_L_ = FinalVolume_ - pCHANSTAT->FinalVolume_R_ ;
4028 /* Surround が有効なら、左チャンネルの位相を反転 */
4029 if( pCHANSTAT->bSurround ){
4030 pCHANSTAT->FinalVolume_L_ = -pCHANSTAT->FinalVolume_L_ ;
4034 /* Period の最終値を求める */
4035 if( pCHANSTAT->pPlayingXM_INSTRUMENT != NULL
4036 && pCHANSTAT->pPlayingXM_SAMPLE != NULL
4039 if( pCHANSTAT->PlayingPeriod_ > pCHANSTAT->PeriodHighLimit_ ){
4040 pCHANSTAT->PlayingPeriod_ = pCHANSTAT->PeriodHighLimit_ ;
4042 if( pCHANSTAT->PlayingPeriod_ < pCHANSTAT->PeriodLowLimit_ ){
4043 pCHANSTAT->PlayingPeriod_ = pCHANSTAT->PeriodLowLimit_ ;
4046 pCHANSTAT->FinalPeriod_ = pCHANSTAT->PlayingPeriod_ ;
4048 /* Arpeggio が有効ならその処理をここで */
4050 if( pCHANSTAT->idxArpeggio == 1 ){
4051 pCHANSTAT->FinalPeriod_ = pCHANSTAT->ArpeggioPeriod_[0] ;
4053 if( pCHANSTAT->idxArpeggio == 2 ){
4054 pCHANSTAT->FinalPeriod_ = pCHANSTAT->ArpeggioPeriod_[1] ;
4056 if( ++pCHANSTAT->idxArpeggio >= 3 ) pCHANSTAT->idxArpeggio = 0 ;
4059 /* Grissando が有効なら、最寄の半音階へ */
4060 if( pCHANSTAT->bGrissando ){
4061 S32 FineTune = pCHANSTAT->PlayingFineTune ;
4062 pCHANSTAT->FinalPeriod_
4063 = MOD__KeyToPeriod_(
4065 ,MOD__Period_ToKey( pMOD ,pCHANSTAT->FinalPeriod_ , FineTune )
4071 Vibrato の反映(Grissando 処理後に行う)
4072 ModPlug では、VolumeColumn の Uxx Hxx の作用と、
4073 メジャーコマンドの 4xy の作用は、互いに加算されない。
4076 S32 Val = _aaWaveTable[
4077 _aVibratoWaveType[ pCHANSTAT->VibratoType & 3 ]
4079 (pCHANSTAT->VibratoPosition_ >> SFT) & 0x3F
4081 pCHANSTAT->VibratoPosition_ += pCHANSTAT->VibratoRate * ModifyVal_ ;
4084 AmigaPeriod モード時、線形周波数モード時、
4085 ともに、最大振幅は -0x7F ~ +0x7F
4087 pCHANSTAT->FinalPeriod_ += (Val << (SFT - 4)) * pCHANSTAT->VibratoDepth ;
4092 ModfyVal_ の倍率は反映しないのが正しい。
4095 S32 InstAutoVibratoType = pCHANSTAT->pPlayingXM_INSTRUMENT->AutoVibratoType ;
4096 S32 InstAutoVibratoSweep = pCHANSTAT->pPlayingXM_INSTRUMENT->AutoVibratoSweep ;
4097 S32 InstAutoVibratoDepth = pCHANSTAT->pPlayingXM_INSTRUMENT->AutoVibratoDepth ;
4098 S32 InstAutoVibratoRate = pCHANSTAT->pPlayingXM_INSTRUMENT->AutoVibratoRate ;
4100 if( InstAutoVibratoDepth
4101 && InstAutoVibratoRate
4103 if( InstAutoVibratoSweep ){
4104 if( pCHANSTAT->bFadeOut == FALSE ){
4105 pCHANSTAT->AutoVibratoDepth_ += (InstAutoVibratoDepth << SFT) / InstAutoVibratoSweep ;
4106 if( pCHANSTAT->AutoVibratoDepth_ > (InstAutoVibratoDepth << SFT) ){
4107 pCHANSTAT->AutoVibratoDepth_ = (InstAutoVibratoDepth << SFT) ;
4111 pCHANSTAT->AutoVibratoDepth_ = (InstAutoVibratoDepth << SFT) ;
4113 pCHANSTAT->AutoVibratoPosition += InstAutoVibratoRate ;
4115 /* 最大振幅 -AutoVibratoDepth ~ +AutoVibratoDepth */
4117 if( InstAutoVibratoType > 4 ) InstAutoVibratoType = 0 ;
4118 if( InstAutoVibratoType == 4 ){
4119 /* 例外的に、波形速度に依存しないランダム波を使用 */
4120 pCHANSTAT->FinalPeriod_ += ((rand() & 0x1FF) - 0x100) * pCHANSTAT->AutoVibratoDepth_ >> 7 ;
4122 pCHANSTAT->FinalPeriod_ += ( _aaWaveTable[
4123 _aAutoVibratoWaveType[ InstAutoVibratoType ]
4125 (pCHANSTAT->AutoVibratoPosition >> 2) & 0x3F
4126 ] * pCHANSTAT->AutoVibratoDepth_
4135 if( pCHANSTAT->pPlayingXM_SAMPLE != NULL ){
4136 if( pCHANSTAT->FinalPeriod_
4137 && pMOD->nWavePerSec
4141 if( pMOD->XmHeader.Flags & LINEAR_FREQUENCY ){
4144 * pow( 2 , ((F64)(6*12*16*4) - (F64)pCHANSTAT->FinalPeriod_ / (F64)ONE) / (F64)(12*16*4) );
4146 /* AmigaPeriod モード */
4147 F64 AmigaClock = 3579364 ;
4148 if( pMOD->FormatType == TYPE_MOD ) AmigaClock = 3546894.6 ;
4149 f64Freq = AmigaClock * 4 / ((F64)pCHANSTAT->FinalPeriod_ / (F64)ONE) ;
4152 pCHANSTAT->SampleRate_ = (U32)(f64Freq * (F64)ONE / (F64)pMOD->nWavePerSec) ;
4159 } /* end of while */
4163 /* 一定時間で 1 Row 進む */
4164 if( pMOD->TickCount >= pMOD->nTickPerRow * (1 + pMOD->PatternDelay) + pMOD->FinePatternDelay ){
4165 #if (WARNING_LEVEL >= 3)
4166 LogMsg(pMOD->Instance,
4171 pMOD->TickCount = 0 ;
4172 pMOD->PatternDelay = 0 ;
4173 pMOD->FinePatternDelay = 0 ;
4176 if( pMOD->BreakSequence != -1 ){
4177 pMOD->idxSequenceData = pMOD->BreakSequence ;
4178 pMOD->BreakSequence = -1 ;
4179 pMOD->Row = -1 ; /* 直後にインクリメントされるので -1 */
4180 MOD__InitPatternLoop( pMOD );
4184 if( pMOD->BreakRow != -1 ){
4185 pMOD->Row = pMOD->BreakRow ;
4186 pMOD->BreakRow = -1 ;
4191 /* パターン末端に達した場合の処理 */
4193 XM_PATTERN *pXM_PATTERN
4194 = pMOD->apXM_PATTERN[ pMOD->XmHeader.aPatternOrderTable[ pMOD->idxSequenceData ] ];
4195 if( pXM_PATTERN != NULL ){
4196 if( pMOD->Row >= pXM_PATTERN->NumberOfRowsInPattern ){
4198 pMOD->idxSequenceData++ ;
4199 MOD__InitPatternLoop( pMOD );
4202 /* 万が一 NULL なら終点に達したとみなす */
4203 pMOD->bDone = TRUE ;
4208 if( pMOD->idxSequenceData >= 256 ){
4209 pMOD->bDone = TRUE ;
4211 if( pMOD->XmHeader.aPatternOrderTable[ pMOD->idxSequenceData ] == 0xFF
4212 || pMOD->idxSequenceData >= pMOD->XmHeader.SongLength
4214 pMOD->bDone = TRUE ; /* 最後まで再生しきった */
4220 ここまでたどり着いた時点で、1 tick 分の波形の出力が許される。
4222 実は、1 tick 分の波形数を調整することで、正確な BPM を再現する仕組み。
4223 nWavePerTick の算式は様々なプレイヤーで同一のモノ。内容はイマイチ良く分からない。
4225 pMOD->nWavePerTick = (pMOD->nWavePerSec * 5) / (pMOD->BPM * 2);
4226 pMOD->nRestWave += pMOD->nWavePerTick ;
4232 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4237 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
4239 MOD *p /* this ポインター */
4241 if( p == NULL ) return( FALSE );
4243 if( MOD__ReleaseSong( p ) == FALSE ) return( FALSE );
4250 /*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4255 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
4256 MOD *MOD__Create(void* Instance){
4258 size_t size = sizeof( MOD );
4259 MOD *p = reinterpret_cast<MOD*>(AllocMemory( size ));
4261 if( p == NULL ) return( NULL );
4264 for( i=0 ; i<size ; i++ ) ((U8*)p)[i] = 0 ;
4267 p->FormatType = TYPE_NOTAVAILABLE ;
4268 p->nWavePerSec = 44100 ;
4269 p->bLoopMode = TRUE ;
4270 p->bAutoGainControl = TRUE ;
4271 p->GlobalVolumeScale_ = ONE ;
4272 for( i=0 ; i<MAX_PATTERNS ; i++ ) p->apXM_PATTERN[ i ] = NULL ;
4273 for( i=0 ; i<MAX_INSTRUMENTS ; i++ ) p->apXM_INSTRUMENT[ i ] = NULL ;
4274 for( i=0 ; i<MAX_SAMPLES ; i++ ) p->apXM_SAMPLE[ i ] = NULL ;
4275 p->Instance = Instance;