📄 s3mfile.c
字号:
/* * $Id: s3mfile.c 1.7 1996/09/13 15:10:01 chasan released $ * * Scream Tracker 3.0 module file loader routines. * * Copyright (c) 1995-1999 Carlos Hasan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */#include <stdio.h>#include <malloc.h>#include <string.h>#include "audio.h"#include "iofile.h"/* * ScreamTracker 3.0 module file structures */#define S3M_MAX_TRACKS 32#define S3M_MAX_SAMPLES 100#define S3M_MAX_PATTERNS 256#define S3M_MAX_ORDERS 256#define S3M_MAX_ROWS 64#define S3M_SCRM_MAGIC 0x4D524353L#define S3M_SCRS_MAGIC 0x53524353L#define S3M_SCRS_PCM 0x01#define S3M_SCRS_LOOPED 0x01typedef struct { CHAR aModuleName[28]; BYTE bPadding; BYTE nFileType; WORD wReserved; WORD nSongLength; WORD nSamples; WORD nPatterns; WORD wFlags; WORD wVersion; WORD nSampleType; DWORD dwSCRM; BYTE nGlobalVolume; BYTE nTempo; BYTE nBPM; BYTE nMasterVolume; BYTE nUltraClick; BYTE nDefaultPanning; BYTE aReserved[8]; WORD wSpecial; BYTE aChannelTable[32];} S3MFILEHEADER;typedef struct { BYTE nType; CHAR aFileName[13]; WORD wDataSegPtr; DWORD dwLength; DWORD dwLoopStart; DWORD dwLoopEnd; BYTE nVolume; BYTE nReserved; BYTE nPacking; BYTE bFlags; DWORD nSampleRate; BYTE aReserved[12]; CHAR aSampleName[28]; DWORD dwSCRS;} S3MSAMPLEHEADER;typedef struct { WORD nSize; LPBYTE lpData;} S3MPATTERNHEADER;typedef struct { BYTE nNote; BYTE nSample; BYTE nVolume; BYTE nCommand; BYTE nParams;} S3MTRACKDATA;#define ACC 11#define MUL(a,b) (((a)*(b)+(1<<(ACC-1)))>>ACC)#define A (LONG)(12.0 * -2.4991805816500 * (1 << ACC))#define B (LONG)(12.0 * +4.0305172865900 * (1 << ACC))#define C (LONG)(12.0 * -2.0791605988100 * (1 << ACC))#define D (LONG)(12.0 * +0.6262992372690 * (1 << ACC))#define E (LONG)(12.0 * -0.0784753434027 * (1 << ACC))static LONG S3MGetRelativeNote(LONG dwSampleRate){ LONG dwRelativeNote; /* * Compute the relative note value given a sampling frequency: * RelativeNote = 12.0 * log2(SampleRate / 8363.0) * * The following algorithm uses 21.11 fixed-point arithmetic * with an accuracy of about 1/128 for sampling frequencies * between 522 and 65535 Hertz. (Thanks Zed!) */ dwSampleRate = (dwSampleRate << (ACC + 4)) / 8363; dwRelativeNote = -48L << ACC; while (dwSampleRate > (2L << ACC)) { dwSampleRate = (dwSampleRate + 1) >> 1; dwRelativeNote += (12L << ACC); } dwRelativeNote += A + MUL(B + MUL(C + MUL(D + MUL(E, dwSampleRate), dwSampleRate), dwSampleRate), dwSampleRate); return dwRelativeNote >> (ACC - 7);}static UINT S3MDecodePattern(UINT nTracks, LPBYTE lpData, UINT nSize, BYTE aMappingTable[], LPAUDIOPATTERN lpPattern){ static S3MTRACKDATA aTrackTable[S3M_MAX_TRACKS]; static BYTE aParamTable[S3M_MAX_TRACKS]; UINT nRow, nTrack, nFlags, nNote, nSample, nVolume, nCommand, nParams; LPBYTE lpFTData, lpEndData; /* initialize the pattern structure */ lpPattern->nPacking = 0; lpPattern->nTracks = nTracks; lpPattern->nRows = S3M_MAX_ROWS; lpPattern->nSize = 0; if ((lpPattern->lpData = malloc(nTracks * 6 * S3M_MAX_ROWS)) == NULL) { return AUDIO_ERROR_NOMEMORY; } lpFTData = lpPattern->lpData; lpEndData = lpData + nSize; memset(aParamTable, 0, sizeof(aParamTable)); for (nRow = 0; nRow < S3M_MAX_ROWS; nRow++) { /* grab the next row of notes from the S3M pattern */ memset(aTrackTable, 0, sizeof(aTrackTable)); while (lpData < lpEndData && (nFlags = *lpData++) != 0x00) { /* get the note event */ nNote = 0xFF; nSample = 0x00; nVolume = 0xFF; nCommand = 0x00; nParams = 0x00; nTrack = nFlags & 0x1F; if (nFlags & 0x20) { nNote = *lpData++; nSample = *lpData++; } if (nFlags & 0x40) { nVolume = *lpData++; } if (nFlags & 0x80) { nCommand = *lpData++; nParams = *lpData++; } /* skip notes for non-PCM tracks */ if ((nTrack = aMappingTable[nTrack]) >= nTracks) continue; /* decode note index */ if (nNote == 0xFE) { nNote = AUDIO_MAX_NOTES + 1; } else if (nNote == 0xFF) { nNote = 0x00; } else { nNote = 12 * (nNote >> 4) + (nNote & 0x0F) + 1; if (nNote > AUDIO_MAX_NOTES) nNote = 0; } /* decode S3M command effect default parameter stuff */ nCommand += 0x40; if (nParams != 0x00) { aParamTable[nTrack] = nParams; } else if (strchr("DEFGKLQ", nCommand)) { nParams = aParamTable[nTrack]; } /* decode S3M command effect */ switch (nCommand) { case '@': /* null command */ nCommand = nParams = 0x00; break; case 'A': /* set tempo speed */ if (nParams < 0x20) { nCommand = 0x0F; } else { /* WARNING: tempo greater than 31 are not supported! */ nCommand = nParams = 0x00; } break; case 'B': /* jump position */ nCommand = 0x0B; break; case 'C': /* break pattern */ nCommand = 0x0D; break; case 'D': if ((nParams & 0xF0) == 0x00) { /* volume slide down */ nCommand = 0x0A; nParams &= 0x0F; } else if ((nParams & 0x0F) == 0x00) { /* volume slide up */ nCommand = 0x0A; nParams &= 0xF0; } else if ((nParams & 0xF0) == 0xF0) { /* fine volume slide down */ nCommand = 0x0E; nParams = 0xB0 | (nParams & 0x0F); } else if ((nParams & 0x0F) == 0x0F) { /* fine volume slide up */ nCommand = 0x0E; nParams = 0xA0 | (nParams >> 4); } else { nCommand = nParams = 0x00; } break; case 'E': if ((nParams & 0xF0) == 0xF0) { /* fine porta down */ nCommand = 0x0E; nParams = 0x20 | (nParams & 0x0F); } else if ((nParams & 0xF0) == 0xE0) { /* extra fine porta down */ nCommand = 0x21; nParams = 0x20 | (nParams & 0x0F); } else { /* portamento down */ nCommand = 0x02; } break; case 'F': if ((nParams & 0xF0) == 0xF0) { /* fine portamento up */ nCommand = 0x0E; nParams = 0x10 | (nParams & 0x0F); } else if ((nParams & 0xF0) == 0xe0) { /* extra fine portamento up */ nCommand = 0x21; nParams = 0x10 | (nParams & 0x0F); } else { /* portamento up */ nCommand = 0x01; } break; case 'G': /* tone portamento */ nCommand = 0x03; break; case 'H': /* vibrato */ nCommand = 0x04; break; case 'I': /* tremor */ nCommand = 0x1d; break; case 'J': /* arpeggio */ nCommand = 0x00; break; case 'K': /* vibrato & volume slide */ nCommand = 0x06; break; case 'L': /* tone portamento & volume slide */ nCommand = 0x05; break; case 'O': /* set sample offset */ nCommand = 0x09; break; case 'Q': /* multi-retrig */ nCommand = 0x1b; break; case 'R': /* tremolo */ nCommand = 0x07; break; case 'S': /* misc settings */ switch (nParams & 0xF0) { case 0x00: /* set filter on/off */ nCommand = 0x0E; nParams = 0x00 | (nParams & 0x0F); break; case 0x10: /* set glissando control */ nCommand = 0x0E; nParams = 0x30 | (nParams & 0x0F); break; case 0x20: /* set fine-tune */ nCommand = 0x0E; nParams = 0x50 | (nParams & 0x0F); break; case 0x30: /* set tremolo waveform */ nCommand = 0x0E; nParams = 0x70 | (nParams & 0x0F); break; case 0x40: /* set vibrato waveform */ nCommand = 0x0E; nParams = 0x40 | (nParams & 0x0F); break; case 0x80: /* set coarse panning */ nCommand = 0x0E; nParams = 0x80 | (nParams & 0x0F); break; case 0xA0: /* set stereo control */ nCommand = 0x08; switch (nParams & 0x0F) { case 0x00: case 0x02: /* hard left panning */ nParams = 0x00; break; case 0x01: case 0x03: /* hard right panning */ nParams = 0xFF; break; case 0x04: /* left panning */ nParams = 0x40; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -