by ravenger7 » Tue Feb 23, 2010 9:50 pm
This code might need some massaging to work like replacing the diagnostics methods.
- Code: Select all
// ModPlayer.h: interface for the CModPlayer class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(_MODPLAYER_H_)
#define _MODPLAYER_H_
#include <QString>
#include <QStringList>
// The following lines are required in order to use the multi-media functions
#include <mmsystem.h>
enum Effect
{
EFFECT_ARPEGGIO = 0x00,
EFFECT_PORTA_UP = 0x01,
EFFECT_PORTA_DOWN = 0x02,
EFFECT_PORTA_TO_NOTE = 0x03,
EFFECT_VIBRATO = 0x04,
EFFECT_PORTA_AND_VOL = 0x05,
EFFECT_VIBRATO_AND_VOL = 0x06,
EFFECT_TREMOLO = 0x07,
EFFECT_PAN = 0x08,
EFFECT_SAMPLE_OFFSET = 0x09,
EFFECT_VOLUME_SLIDE = 0x0A,
EFFECT_JUMP_TO_PATTERN = 0x0B,
EFFECT_SET_VOLUME = 0x0C,
EFFECT_PATTERN_BREAK = 0x0D,
EFFECT_EXTENDED = 0x0E,
EFFECT_SET_SPEED = 0x0F,
EFFECT_SET_GLOBAL_VOLUME = 0x10,
EFFECT_PANNING_SLIDE = 0x1B
};
enum ExtenedEffects
{
EXTENDED_SET_FILTER = 0x00,
EXTENDED_FINE_PORTA_UP = 0x01,
EXTENDED_FINE_PORTA_DOWN = 0x02,
EXTENDED_GLISSANDO = 0x03,
EXTENDED_VIBRATO_WAVE = 0x04,
EXTENDED_FINE_TUNE = 0x05,
EXTENDED_PATTERN_LOOP = 0x06,
EXTENDED_TREMOLO_WAVE = 0x07,
EXTENDED_PAN = 0x08,
EXTENDED_RETRIG_NOTE = 0x09,
EXTENDED_FINE_VOLUME_UP = 0x0A,
EXTENDED_FINE_VOLUME_DOWN = 0x0B,
EXTENDED_CUT_NOTE = 0x0C,
EXTENDED_DELAY_NOTE = 0x0D,
EXTENDED_PATTERN_DELAY = 0x0E,
EXTENDED_INVERT_LOOP = 0x0F
};
class CModPlayer;
#define NUM_PERIODS 296
#define NUM_NOTES 96
// Patterns[Num_Patterns].Rows[m_Num_Rows].Notes[Num_Tracks]
typedef struct
{
BYTE Sample_Num; // The sample number (ie "instrument") to play, 1->31
BYTE Effect; // Contains the effect code
BYTE Effect_Parms; // Used to store control parameters for the various effects
BYTE Note;
BYTE Volume;
} NoteData;
typedef struct
{
NoteData * Note;
} RowData;
typedef struct
{
RowData Row[256];
int Num_Rows;
} PatternData;
// The Sample structure is used to store all the information for a single sample, or "instrument". Most of the
// member's should be self-explanatory. The "data" member is an array of bytes containing the raw sample data
// in 8-bit signed format.
typedef struct
{
char Name[28];
int Length;
BYTE Volume;
int Loop_Start;
int Loop_End;
BYTE * Data;
int Frequency; // C-5 Frequency
int XM_Note;
int XM_Fine_Tune;
} SampleData;
// This #define is used to convert an Amiga period number to a frequency. The freqency returned
// is the frequency that the sample should be played at.
#define Period2Freq(period) (3579545.0f/(period))
#define Freq2Period(note,sample_freq) (Period_Freq[note] / (sample_freq))
#define LinearPeriod2Freq(period) (8363 * pow(2,(double)(6*12*16*4 - period) / (double)(12*4*16)))
#define LinearFreq2Period(note,sample) (10*12*4*16 - (note + m_Samples[sample].XM_Note)*4*16 - m_Samples[sample].XM_Fine_Tune/2)
extern float Period_Freq[96];
extern WORD FineTuneFrequency[16];
// TrackData is used to store ongoing information about a particular track.
typedef struct
{
BYTE Sample; // The current sample being played (0 for none)
int Pos; // The current playback position in the sample, stored in fixed-point format
short Period; // The period number that period_index corresponds to (needed for various effects)
BYTE Note; // Note to play 8 octaves, 12 notes per octave = 96 total notes
BYTE Next_Note; // Note to Porta or Delay to
float Freq; // This is the actual frequency used to do the mixing. It's a combination of the value calculated from the period member and an "adjustment" made by various effects.
BYTE Volume; // Volume that this track is to be mixed at
BYTE Mix_Volume; // This is the actual volume used to do the mixing. It's a combination of the volume member and an "adjustment" made by various effects.
short Porta; // Used by the porta effect, this stores the note we're porta-ing (?) to
short Porta_Speed; // The speed at which to porta
short Vib_Speed; // Vibrato speed
short Vib_Depth; // Vibrato depth
short Trem_Speed; // Tremolo speed
short Trem_Depth; // Tremolo depth
BYTE Retrig_Tick; // Tick to retrig on
BYTE Delay_Tick; // Tick to delay to
BYTE Pan; // Pan value 0x00 Left, 0x40 Center, 0x80 Right
int Sine_Pos; // These next two values are pointers to the sine table. They're used to do
int Sine_Neg; // various effects.
} TrackData;
// The following structure is used to store all the information for a particular block of sound.
// This is needed so that the callback function can clean it up once it's played.
typedef struct SoundBlockType
{
CModPlayer * Tracker; // Pointer to the parent player object
LPBYTE Sound_Data; // Points to the actual sound data
LPWAVEHDR Wave_Header;
SoundBlockType * Next_Block;
} SoundBlock;
class CModPlayer
{
public:
CModPlayer(QString filename,int frequency,BOOL stereo,BOOL surround,BOOL oversample,BOOL looping);
virtual ~CModPlayer();
void SetMasterVolume(int volume);
int GetMasterVolume() { return m_Master_Volume; }
BOOL Play(int order = 0,int row = 0);
BOOL Stop();
BOOL Pause();
BOOL IsPaused() { return m_Paused; }
BOOL IsPlaying() { return m_Playing; }
BOOL IsFinished() { return m_Order >= m_Song_Length && m_Finished && m_Blocks == NULL; }
int GetOrder() { return m_Order; }
int GetRow() { return m_Row; }
int GetLength() { return m_Song_Length; }
const char * GetSongName() { return m_Song_Name; }
void GetSampleNames(QStringList & list);
int GetNumPatterns() { return m_Num_Patterns; }
int GetNumTracks() { return m_Num_Tracks; }
private:
int ConvertMODWord(WORD data);
int ConvertWord(BYTE * data,int & index);
// Loading functions defined in Loader.cpp
BOOL LoadMOD(BYTE * data,int length);
BOOL LoadS3M(BYTE * data,int length);
BOOL LoadSTM(BYTE * data,int length);
BOOL Load669(BYTE * data,int length);
BOOL LoadWOW(BYTE * data,int length);
BOOL LoadMTM(BYTE * data,int length);
BOOL LoadXM (BYTE * data,int length);
// Do special effects
void DoTremalo(int track);
void DoVibrato(int track);
void DoPorta(int track);
void DoSlideVolume(int track, int amount);
void UpdateEffects();
void UpdateRow();
BOOL MixChunk();
BOOL MixSubChunk(int * left,int * right,int numsamples);
int MixTrack(int track,int * buffer,int volume,int numsamples);
void AddBlock(SoundBlock * block);
void RemoveBlock();
static DWORD WINAPI ThreadProc(LPVOID param);
static void CALLBACK waveOutProc(HWAVEOUT hwo,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2);
short m_Volume_Table[65][256];
char m_Song_Name[28];
BYTE m_Song_Length;
BYTE m_Orders[128];
PatternData * m_Patterns;
BYTE m_Num_Patterns;
SampleData * m_Samples;
BYTE m_Num_Samples;
BYTE m_Default_Pan[32];
TrackData * m_Track_Data; // Stores info for each track being played
int m_Speed; // Speed of mod being played
BYTE m_Order; // Current order being played
BYTE m_Row; // Current row being played
int m_Tick; // Current tick number (there are "m_Speed" ticks between each row)
int m_BPM; // Beats-per-minute...controls length of each tick
HWAVEOUT m_Wave_Handle; // Handle to the wave device
int m_Samples_Left; // Number of samples left to mix for the current tick
BYTE m_Num_Tracks; // Number of tracks in this mod
RowData * m_Current_Row; // Pointer to the current row being played
BOOL m_Playing; // Set to true when a mod is being played
int * m_Left_Buffer; // Used to delay the left tracks when they're played to the right channel
int * m_Right_Buffer; // Used to delay the right tracks when they're played to the left channel
int m_Frequency; // Sound playback frequency
BOOL m_Over_Sample;
BOOL m_Surround;
BOOL m_Stereo;
BYTE m_Num_Channels; // 2 for stereo, 1 for mono
HANDLE m_Mixing_Thread;
HANDLE m_Mix_Event;
BOOL m_Paused;
BOOL m_Looping;
BOOL m_Finished;
SoundBlock * m_Blocks; // Blocks to free on next thread loop
int m_Surround_Delay;
CRITICAL_SECTION m_Critical_Section;
int m_Sample_Rate; // Rate samples are added to sound buffer (Frequency / 5 or something)
BOOL m_Loaded; // Successfully loaded the file
LONG m_Blocks_To_Mix;
int m_Master_Volume;
BOOL m_Linear_Frequency;
};
#endif