📄 s3mfile.c
字号:
case 0x05: /* right panning */ nParams = 0xC0; break; case 0x06: case 0x07: /* middle panning */ nParams = 0x80; break; default: nCommand = nParams = 0x00; break; } break; case 0xB0: /* set/start pattern loop */ nCommand = 0x0E; nParams = 0x60 | (nParams & 0x0F); break; case 0xC0: /* note cut */ nCommand = 0x0E; nParams = 0xC0 | (nParams & 0x0F); break; case 0xD0: /* note delay */ nCommand = 0x0E; nParams = 0xD0 | (nParams & 0x0F); break; case 0xE0: /* pattern delay */ nCommand = 0x0E; nParams = 0xE0 | (nParams & 0x0F); break; default: nCommand = nParams = 0x00; break; } break; case 'T': /* set BPM speed */ if (nParams >= 0x20) nCommand = 0x0F; else nCommand = nParams = 0x00; break; case 'U': /* fine vibrato */ /* WARNING: this is not an standard FT2 command! */ nCommand = 0x1E; break; case 'V': /* set global volume */ nCommand = 0x10; break; case 'X': /* set DMP-style panning */ nCommand = 0x08; if (nParams > 0x80) nParams = 0x80; else if (nParams < 0x80) nParams <<= 1; else nParams = 0xFF; break; case 'Z': /* set sync mark */ /* WARNING: this is not an standard FT2 command! */ nCommand = 0x23; break; default: /* unknown S3M command value */ nCommand = nParams = 0x00; break; } /* save note message */ if (nNote) { aTrackTable[nTrack].nNote = nNote; } if (nSample) { aTrackTable[nTrack].nSample = nSample; } if (nVolume <= 64) { aTrackTable[nTrack].nVolume = 0x10 + nVolume; } if (nCommand | nParams) { aTrackTable[nTrack].nCommand = nCommand; aTrackTable[nTrack].nParams = nParams; } } /* encode row of notes in our pattern structure */ for (nTrack = 0; nTrack < nTracks; nTrack++) { /* get saved note message */ nNote = aTrackTable[nTrack].nNote; nSample = aTrackTable[nTrack].nSample; nVolume = aTrackTable[nTrack].nVolume; nCommand = aTrackTable[nTrack].nCommand; nParams = aTrackTable[nTrack].nParams; /* insert new note message */ nFlags = AUDIO_PATTERN_PACKED; if (nNote) nFlags |= AUDIO_PATTERN_NOTE; if (nSample) nFlags |= AUDIO_PATTERN_SAMPLE; if (nVolume) nFlags |= AUDIO_PATTERN_VOLUME; if (nCommand) nFlags |= AUDIO_PATTERN_COMMAND; if (nParams) nFlags |= AUDIO_PATTERN_PARAMS; *lpFTData++ = nFlags; if (nNote) *lpFTData++ = nNote; if (nSample) *lpFTData++ = nSample; if (nVolume) *lpFTData++ = nVolume; if (nCommand) *lpFTData++ = nCommand; if (nParams) *lpFTData++ = nParams; } } lpPattern->nSize = (lpFTData - lpPattern->lpData); if ((lpPattern->lpData = realloc(lpPattern->lpData, lpPattern->nSize)) == NULL) { return AUDIO_ERROR_NOMEMORY; } return AUDIO_ERROR_NONE;}static VOID S3MDecodeSample(LPBYTE lpData, UINT nSize){ /* convert from 8-bit unsigned to 8-bit signed linear */ while (nSize--) { *lpData++ ^= 0x80; }}UINT AIAPI ALoadModuleS3M(LPSTR lpszFileName, LPAUDIOMODULE *lplpModule, DWORD dwFileOffset){ static S3MFILEHEADER Header; static S3MSAMPLEHEADER Sample; static S3MPATTERNHEADER Pattern; static WORD aSampleSegPtr[S3M_MAX_SAMPLES]; static WORD aPatternSegPtr[S3M_MAX_PATTERNS]; static BYTE aPanningTable[S3M_MAX_TRACKS]; static BYTE aMappingTable[S3M_MAX_TRACKS]; LPAUDIOMODULE lpModule; LPAUDIOPATTERN lpPattern; LPAUDIOPATCH lpPatch; LPAUDIOSAMPLE lpSample; LONG dwRelativeNote; UINT n, nErrorCode; if (AIOOpenFile(lpszFileName)) { return AUDIO_ERROR_FILENOTFOUND; } AIOSeekFile(dwFileOffset, SEEK_SET); if ((lpModule = (LPAUDIOMODULE) calloc(1, sizeof(AUDIOMODULE))) == NULL) { AIOCloseFile(); return AUDIO_ERROR_NOMEMORY; } /* load S3M module file header */ AIOReadFile(Header.aModuleName, sizeof(Header.aModuleName)); AIOReadChar(&Header.bPadding); AIOReadChar(&Header.nFileType); AIOReadShort(&Header.wReserved); AIOReadShort(&Header.nSongLength); AIOReadShort(&Header.nSamples); AIOReadShort(&Header.nPatterns); AIOReadShort(&Header.wFlags); AIOReadShort(&Header.wVersion); AIOReadShort(&Header.nSampleType); AIOReadLong(&Header.dwSCRM); AIOReadChar(&Header.nGlobalVolume); AIOReadChar(&Header.nTempo); AIOReadChar(&Header.nBPM); AIOReadChar(&Header.nMasterVolume); AIOReadChar(&Header.nUltraClick); AIOReadChar(&Header.nDefaultPanning); AIOReadFile(Header.aReserved, sizeof(Header.aReserved)); AIOReadShort(&Header.wSpecial); AIOReadFile(Header.aChannelTable, sizeof(Header.aChannelTable)); if (Header.dwSCRM != S3M_SCRM_MAGIC || Header.nSongLength > S3M_MAX_ORDERS || Header.nPatterns > S3M_MAX_PATTERNS || Header.nSamples > S3M_MAX_SAMPLES) { AFreeModuleFile(lpModule); AIOCloseFile(); return AUDIO_ERROR_BADFILEFORMAT; } /* load S3M order table and sample/pattern para-pointers */ AIOReadFile(lpModule->aOrderTable, Header.nSongLength); for (n = 0; n < Header.nSamples; n++) { AIOReadShort(&aSampleSegPtr[n]); } for (n = 0; n < Header.nPatterns; n++) { AIOReadShort(&aPatternSegPtr[n]); } /* load S3M panning table if present */ memset(aPanningTable, 0x00, sizeof(aPanningTable)); if (Header.nDefaultPanning == 0xFC) { AIOReadFile(aPanningTable, sizeof(aPanningTable)); } /* fixup the S3M panning table */ for (n = 0; n < S3M_MAX_TRACKS; n++) { if (aPanningTable[n] & 0x20) { aPanningTable[n] = (aPanningTable[n] & 0x0F) << 4; } else { if (Header.aChannelTable[n] <= 7) { aPanningTable[n] = 0x00; } else if (Header.aChannelTable[n] <= 15) { aPanningTable[n] = 0xFF; } } } /* initialize the module structure */ strncpy(lpModule->szModuleName, Header.aModuleName, sizeof(lpModule->szModuleName) - 1); lpModule->wFlags = AUDIO_MODULE_AMIGA | AUDIO_MODULE_PANNING; lpModule->nPatterns = Header.nPatterns; lpModule->nPatches = Header.nSamples; lpModule->nTempo = Header.nTempo; lpModule->nBPM = Header.nBPM; for (n = 0; n < Header.nSongLength; n++) { if (lpModule->aOrderTable[n] < Header.nPatterns) { lpModule->aOrderTable[lpModule->nOrders++] = lpModule->aOrderTable[n]; } else { lpModule->aOrderTable[n] = 0x00; } } /* lpModule->nRestart = lpModule->nOrders; */ for (n = 0; n < S3M_MAX_TRACKS; n++) { aMappingTable[n] = 0xFF; if ((Header.aChannelTable[n] &= 0x7F) <= 15) { aMappingTable[n] = (BYTE) lpModule->nTracks; lpModule->aPanningTable[lpModule->nTracks++] = aPanningTable[n]; } } if ((lpModule->aPatternTable = (LPAUDIOPATTERN) calloc(lpModule->nPatterns, sizeof(AUDIOPATTERN))) == NULL) { AFreeModuleFile(lpModule); AIOCloseFile(); return AUDIO_ERROR_NOMEMORY; } if ((lpModule->aPatchTable = (LPAUDIOPATCH) calloc(lpModule->nPatches, sizeof(AUDIOPATCH))) == NULL) { AFreeModuleFile(lpModule); AIOCloseFile(); return AUDIO_ERROR_NOMEMORY; } /* load S3M pattern sheets */ lpPattern = lpModule->aPatternTable; for (n = 0; n < lpModule->nPatterns; n++, lpPattern++) { AIOSeekFile(((LONG) aPatternSegPtr[n] << 4) + dwFileOffset, SEEK_SET); AIOReadShort(&Pattern.nSize); Pattern.nSize -= sizeof(Pattern.nSize); if ((Pattern.lpData = malloc(Pattern.nSize)) == NULL) { AFreeModuleFile(lpModule); AIOCloseFile(); return AUDIO_ERROR_NOMEMORY; } AIOReadFile(Pattern.lpData, Pattern.nSize); nErrorCode = S3MDecodePattern(lpModule->nTracks, Pattern.lpData, Pattern.nSize, aMappingTable, lpPattern); free(Pattern.lpData); if (nErrorCode != AUDIO_ERROR_NONE) { AFreeModuleFile(lpModule); AIOCloseFile(); return nErrorCode; } } /* load S3M sample waveforms */ lpPatch = lpModule->aPatchTable; for (n = 0; n < lpModule->nPatches; n++, lpPatch++) { /* load S3M sample header structure */ AIOSeekFile(((LONG) aSampleSegPtr[n] << 4) + dwFileOffset, SEEK_SET); AIOReadChar(&Sample.nType); AIOReadFile(&Sample.aFileName, sizeof(Sample.aFileName)); AIOReadShort(&Sample.wDataSegPtr); AIOReadLong(&Sample.dwLength); AIOReadLong(&Sample.dwLoopStart); AIOReadLong(&Sample.dwLoopEnd); AIOReadChar(&Sample.nVolume); AIOReadChar(&Sample.nReserved); AIOReadChar(&Sample.nPacking); AIOReadChar(&Sample.bFlags); AIOReadLong(&Sample.nSampleRate); AIOReadFile(Sample.aReserved, sizeof(Sample.aReserved)); AIOReadFile(Sample.aSampleName, sizeof(Sample.aSampleName)); AIOReadLong(&Sample.dwSCRS); if (Sample.nType == S3M_SCRS_PCM && Sample.dwSCRS != S3M_SCRS_MAGIC) { AFreeModuleFile(lpModule); AIOCloseFile(); return AUDIO_ERROR_BADFILEFORMAT; } /* initialize patch structure */ strncpy(lpPatch->szPatchName, Sample.aSampleName, sizeof(lpPatch->szPatchName) - 1); if (Sample.nType == S3M_SCRS_PCM && Sample.dwLength != 0) { if ((lpSample = (LPAUDIOSAMPLE) calloc(1, sizeof(AUDIOSAMPLE))) == NULL) { AFreeModuleFile(lpModule); AIOCloseFile(); return AUDIO_ERROR_NOMEMORY; } lpPatch->nSamples = 1; lpPatch->aSampleTable = lpSample; /* initialize sample structure */ lpSample->Wave.wFormat = AUDIO_FORMAT_8BITS; if (Sample.bFlags & S3M_SCRS_LOOPED) lpSample->Wave.wFormat |= AUDIO_FORMAT_LOOP; lpSample->Wave.dwLength = Sample.dwLength; lpSample->Wave.dwLoopStart = Sample.dwLoopStart; lpSample->Wave.dwLoopEnd = Sample.dwLoopEnd; lpSample->Wave.nSampleRate = (WORD) Sample.nSampleRate; lpSample->nVolume = Sample.nVolume; lpSample->nPanning = (AUDIO_MIN_PANNING + AUDIO_MAX_PANNING) / 2; /* compute fine tuning for this sample */ if (Sample.nSampleRate != 0) { dwRelativeNote = S3MGetRelativeNote(Sample.nSampleRate); lpSample->nRelativeNote = (BYTE) (dwRelativeNote >> 7); lpSample->nFinetune = (dwRelativeNote & 0x7F); } /* allocate sample waveform data */ nErrorCode = ACreateAudioData(&lpSample->Wave); if (nErrorCode != AUDIO_ERROR_NONE) { AFreeModuleFile(lpModule); AIOCloseFile(); return nErrorCode; } /* load sample wavefrom data */ AIOSeekFile(((LONG) Sample.wDataSegPtr << 4) + dwFileOffset, SEEK_SET); AIOReadFile(lpSample->Wave.lpData, lpSample->Wave.dwLength); S3MDecodeSample(lpSample->Wave.lpData, lpSample->Wave.dwLength); AWriteAudioData(&lpSample->Wave, 0, lpSample->Wave.dwLength); } } AIOCloseFile(); *lplpModule = lpModule; return AUDIO_ERROR_NONE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -