1069 lines
28 KiB
C++
1069 lines
28 KiB
C++
// Some of the original source code for this file can be found here:
|
||
// https://github.com/shbow/organya/blob/master/source/OrgFile.cpp
|
||
// https://github.com/shbow/organya/blob/master/source/OrgPlay.cpp
|
||
// https://github.com/shbow/organya/blob/master/source/Sound.cpp
|
||
// https://github.com/shbow/organya/blob/master/source/WinTimer.cpp
|
||
|
||
#include "Organya.h"
|
||
|
||
#include <stddef.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
#ifdef FIX_BUGS
|
||
// The original source code forgot to set this (you can tell because, in the original EXE,
|
||
// the DSBUFFERDESC structs in this file have a different size to the ones in Sound.cpp)
|
||
#define DIRECTSOUND_VERSION 0x500
|
||
#endif
|
||
#include <dsound.h>
|
||
|
||
#include "WindowsWrapper.h"
|
||
|
||
#include "Sound.h"
|
||
|
||
#define PANDUMMY 0xFF
|
||
#define VOLDUMMY 0xFF
|
||
#define KEYDUMMY 0xFF
|
||
|
||
#define ALLOCNOTE 4096
|
||
|
||
#define DEFVOLUME 200//255はVOLDUMMY。MAXは254
|
||
#define DEFPAN 6
|
||
|
||
//曲情報をセットする時のフラグ
|
||
#define SETALL 0xffffffff//全てをセット
|
||
#define SETWAIT 0x00000001
|
||
#define SETGRID 0x00000002
|
||
#define SETALLOC 0x00000004
|
||
#define SETREPEAT 0x00000008
|
||
#define SETFREQ 0x00000010
|
||
#define SETWAVE 0x00000020
|
||
#define SETPIPI 0x00000040
|
||
|
||
typedef struct ORGANYATRACK
|
||
{
|
||
unsigned short freq; // +α周波数(1000がDefault) (+ α frequency (1000 is Default))
|
||
unsigned char wave_no; // 波形No (Waveform No)
|
||
unsigned char pipi; // ☆
|
||
unsigned short note_num; // 音符の数 (Number of notes)
|
||
} ORGANYATRACK;
|
||
|
||
typedef struct ORGANYADATA
|
||
{
|
||
unsigned short wait;
|
||
unsigned char line;
|
||
unsigned char dot;
|
||
long repeat_x; // リピート (repeat)
|
||
long end_x; // 曲の終わり(リピートに戻る) (End of song (return to repeat))
|
||
ORGANYATRACK tdata[MAXTRACK];
|
||
} ORGANYADATA;
|
||
|
||
// Below are Organya song data structures
|
||
typedef struct NOTELIST
|
||
{
|
||
NOTELIST *from; // Previous address
|
||
NOTELIST *to; // Next address
|
||
|
||
long x; // Position
|
||
unsigned char length; // Sound length
|
||
unsigned char y; // Sound height
|
||
unsigned char volume; // Volume
|
||
unsigned char pan;
|
||
} NOTELIST;
|
||
|
||
// Track data * 8
|
||
typedef struct TRACKDATA
|
||
{
|
||
unsigned short freq; // Frequency (1000 is default)
|
||
unsigned char wave_no; // Waveform No.
|
||
signed char pipi;
|
||
|
||
NOTELIST *note_p;
|
||
NOTELIST *note_list;
|
||
} TRACKDATA;
|
||
|
||
// Unique information held in songs
|
||
typedef struct MUSICINFO
|
||
{
|
||
unsigned short wait;
|
||
unsigned char line; // Number of lines in one measure
|
||
unsigned char dot; // Number of dots per line
|
||
unsigned short alloc_note; // Number of allocated notes
|
||
long repeat_x; // Repeat
|
||
long end_x; // End of song (Return to repeat)
|
||
TRACKDATA tdata[MAXTRACK];
|
||
} MUSICINFO;
|
||
|
||
// メインクラス。このアプリケーションの中心。(クラスってやつを初めて使う) (Main class. The heart of this application. (Class is used for the first time))
|
||
typedef struct OrgData
|
||
{
|
||
OrgData(); // コンストラクタ (Constructor)
|
||
// ~OrgData(); // デストラクタ (Destructor)
|
||
MUSICINFO info;
|
||
char track;
|
||
char mute[MAXTRACK];
|
||
unsigned char def_pan;
|
||
unsigned char def_volume;
|
||
void InitOrgData(void);
|
||
void GetMusicInfo(MUSICINFO *mi); // 曲情報を取得 (Get song information)
|
||
// 曲情報を設定。flagは設定アイテムを指定 (Set song information. flag specifies the setting item)
|
||
BOOL SetMusicInfo(MUSICINFO *mi,unsigned long flag);
|
||
BOOL NoteAlloc(unsigned short note_num); // 指定の数だけNoteDataの領域を確保 (Allocate the specified number of NoteData areas.)
|
||
void ReleaseNote(void); // NoteDataを開放 (Release NoteData)
|
||
// 以下は再生 (The following is playback)
|
||
void PlayData(void);
|
||
void SetPlayPointer(long x); // 再生ポインターを指定の位置に設定 (Set playback pointer to specified position)
|
||
// 以下はファイル関係 (The following are related to files)
|
||
BOOL InitMusicData(const char *path);
|
||
} ORGDATA;
|
||
|
||
LPDIRECTSOUNDBUFFER lpORGANBUFFER[8][8][2] = {NULL};
|
||
|
||
/////////////////////////////////////////////
|
||
//■オルガーニャ■■■■■■■■■■■■/////// (Organya)
|
||
/////////////////////
|
||
|
||
// Wave playing and loading
|
||
typedef struct
|
||
{
|
||
short wave_size;
|
||
short oct_par;
|
||
short oct_size;
|
||
} OCTWAVE;
|
||
|
||
OCTWAVE oct_wave[8] =
|
||
{
|
||
{ 256, 1, 4 }, // 0 Oct
|
||
{ 256, 2, 8 }, // 1 Oct
|
||
{ 128, 4, 12 }, // 2 Oct
|
||
{ 128, 8, 16 }, // 3 Oct
|
||
{ 64, 16, 20 }, // 4 Oct
|
||
{ 32, 32, 24 }, // 5 Oct
|
||
{ 16, 64, 28 }, // 6 Oct
|
||
{ 8,128, 32 }, // 7 Oct
|
||
};
|
||
|
||
WAVEFORMATEX format_tbl2 = {WAVE_FORMAT_PCM, 1, 22050, 22050, 1, 8, 0}; // 22050HzのFormat
|
||
|
||
// In the original source code, format_tbl2 was a raw array of bytes, as seen below
|
||
// BYTE format_tbl2[] = {0x01,0x00,0x01,0x00,0x22,0x56,0x00,0x00,0x22,0x56,0x00,0x00,0x01,0x00,0x08,0x00,0x00,0x00}; // 22050HzのFormat
|
||
|
||
BOOL MakeSoundObject8(signed char *wavep, signed char track, signed char pipi)
|
||
{
|
||
DWORD i,j,k;
|
||
unsigned long wav_tp; // WAVテーブルをさすポインタ (Pointer to WAV table)
|
||
DWORD wave_size; // 256;
|
||
DWORD data_size;
|
||
BYTE *wp;
|
||
BYTE *wp_sub;
|
||
int work;
|
||
// セカンダリバッファの生成 (Create secondary buffer)
|
||
DSBUFFERDESC dsbd;
|
||
|
||
if (lpDS == NULL)
|
||
return FALSE;
|
||
|
||
for (j = 0; j < 8; j++)
|
||
{
|
||
for (k = 0; k < 2; k++)
|
||
{
|
||
wave_size = oct_wave[j].wave_size;
|
||
|
||
if (pipi)
|
||
data_size = wave_size * oct_wave[j].oct_size;
|
||
else
|
||
data_size = wave_size;
|
||
|
||
ZeroMemory(&dsbd, sizeof(dsbd));
|
||
|
||
dsbd.dwSize = sizeof(dsbd);
|
||
dsbd.dwBufferBytes = data_size;
|
||
dsbd.lpwfxFormat = &format_tbl2;
|
||
dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
|
||
|
||
if(lpDS->CreateSoundBuffer(&dsbd, &lpORGANBUFFER[track][j][k], NULL) != DS_OK) // j = se_no
|
||
return FALSE;
|
||
|
||
// Get wave data
|
||
wp = (BYTE*)malloc(data_size);
|
||
wp_sub = wp;
|
||
wav_tp = 0;
|
||
|
||
for (i = 0; i < data_size; i++)
|
||
{
|
||
work = *(wavep + wav_tp);
|
||
work += 0x80;
|
||
|
||
*wp_sub = (BYTE)work;
|
||
|
||
wav_tp += 0x100 / wave_size;
|
||
if (wav_tp > 0xFF)
|
||
wav_tp -= 0x100;
|
||
|
||
wp_sub++;
|
||
}
|
||
|
||
// データの転送 (Data transfer)
|
||
LPVOID lpbuf1, lpbuf2;
|
||
DWORD dwbuf1, dwbuf2=0;
|
||
HRESULT hr;
|
||
|
||
hr = lpORGANBUFFER[track][j][k]->Lock(0, data_size, &lpbuf1, &dwbuf1, &lpbuf2, &dwbuf2, 0);
|
||
|
||
if (hr != DS_OK)
|
||
{
|
||
#ifdef FIX_BUGS
|
||
free(wp); // The updated Organya source code includes this fix
|
||
#endif
|
||
return FALSE;
|
||
}
|
||
|
||
CopyMemory(lpbuf1, (BYTE*)wp, dwbuf1);
|
||
|
||
if (dwbuf2 != 0)
|
||
CopyMemory(lpbuf2, (BYTE*)wp+dwbuf1, dwbuf2);
|
||
|
||
lpORGANBUFFER[track][j][k]->Unlock(lpbuf1, dwbuf1, lpbuf2, dwbuf2);
|
||
lpORGANBUFFER[track][j][k]->SetCurrentPosition(0);
|
||
free(wp);
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
short freq_tbl[12] = {262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494};
|
||
|
||
void ChangeOrganFrequency(unsigned char key, signed char track, long a)
|
||
{
|
||
if (lpDS == NULL)
|
||
return;
|
||
|
||
for (int j = 0; j < 8; j++)
|
||
for (int i = 0; i < 2; i++)
|
||
lpORGANBUFFER[track][j][i]->SetFrequency(((oct_wave[j].wave_size * freq_tbl[key]) * oct_wave[j].oct_par) / 8 + (a - 1000)); // 1000を+αのデフォルト値とする (1000 is the default value for + α)
|
||
}
|
||
|
||
BOOL g_mute[MAXTRACK]; // Used by the debug Mute menu
|
||
short pan_tbl[13] = {0, 43, 86, 129, 172, 215, 256, 297, 340, 383, 426, 469, 512};
|
||
unsigned char old_key[MAXTRACK] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // 再生中の音 (Sound being played)
|
||
unsigned char key_on[MAXTRACK]; // キースイッチ (Key switch)
|
||
unsigned char key_twin[MAXTRACK]; // 今使っているキー(連続時のノイズ防止の為に二つ用意) (Currently used keys (prepared for continuous noise prevention))
|
||
|
||
void ChangeOrganPan(unsigned char key, unsigned char pan, signed char track) // 512がMAXで256がノーマル (512 is MAX and 256 is normal)
|
||
{
|
||
if (lpDS == NULL)
|
||
return;
|
||
|
||
if (old_key[track] != PANDUMMY)
|
||
lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->SetPan((pan_tbl[pan] - 0x100) * 10);
|
||
}
|
||
|
||
void ChangeOrganVolume(int no, long volume, signed char track) // 300がMAXで300がノーマル (300 is MAX and 300 is normal)
|
||
{
|
||
if (lpDS == NULL)
|
||
return;
|
||
|
||
if (old_key[track] != VOLDUMMY)
|
||
lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->SetVolume((volume - 0xFF) * 8);
|
||
}
|
||
|
||
// サウンドの再生 (Play sound)
|
||
void PlayOrganObject(unsigned char key, int mode, signed char track, long freq)
|
||
{
|
||
if (lpDS == NULL)
|
||
return;
|
||
|
||
if (lpORGANBUFFER[track][key / 12][key_twin[track]] != NULL)
|
||
{
|
||
switch (mode)
|
||
{
|
||
case 0: // 停止 (Stop)
|
||
if (old_key[track] != 0xFF)
|
||
{
|
||
lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Stop();
|
||
lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->SetCurrentPosition(0);
|
||
}
|
||
break;
|
||
|
||
case 1: // 再生 (Playback)
|
||
break;
|
||
|
||
case 2: // 歩かせ停止 (Stop playback)
|
||
if (old_key[track] != 0xFF)
|
||
{
|
||
lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Play(0, 0, 0);
|
||
old_key[track] = 0xFF;
|
||
}
|
||
break;
|
||
|
||
case -1:
|
||
if (old_key[track] == 0xFF) // 新規鳴らす (New sound)
|
||
{
|
||
ChangeOrganFrequency(key % 12, track, freq); // 周波数を設定して (Set the frequency)
|
||
lpORGANBUFFER[track][key / 12][key_twin[track]]->Play(0, 0, DSBPLAY_LOOPING);
|
||
old_key[track] = key;
|
||
key_on[track] = 1;
|
||
}
|
||
else if (key_on[track] == 1 && old_key[track] == key) // 同じ音 (Same sound)
|
||
{
|
||
// 今なっているのを歩かせ停止 (Stop playback now)
|
||
lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Play(0, 0, 0);
|
||
key_twin[track]++;
|
||
if (key_twin[track] > 1)
|
||
key_twin[track] = 0;
|
||
lpORGANBUFFER[track][key / 12][key_twin[track]]->Play(0, 0, DSBPLAY_LOOPING);
|
||
}
|
||
else // 違う音を鳴らすなら (If you make a different sound)
|
||
{
|
||
lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Play(0, 0, 0); // 今なっているのを歩かせ停止 (Stop playback now)
|
||
key_twin[track]++;
|
||
if (key_twin[track] > 1)
|
||
key_twin[track] = 0;
|
||
ChangeOrganFrequency(key % 12, track, freq); // 周波数を設定して (Set the frequency)
|
||
lpORGANBUFFER[track][key / 12][key_twin[track]]->Play(0, 0, DSBPLAY_LOOPING);
|
||
old_key[track] = key;
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// オルガーニャオブジェクトを開放 (Open Organya object)
|
||
void ReleaseOrganyaObject(signed char track)
|
||
{
|
||
if (lpDS == NULL)
|
||
return;
|
||
|
||
for (int i = 0; i < 8; i++)
|
||
{
|
||
if (lpORGANBUFFER[track][i][0] != NULL)
|
||
{
|
||
lpORGANBUFFER[track][i][0]->Release();
|
||
lpORGANBUFFER[track][i][0] = NULL;
|
||
}
|
||
if (lpORGANBUFFER[track][i][1] != NULL)
|
||
{
|
||
lpORGANBUFFER[track][i][1]->Release();
|
||
lpORGANBUFFER[track][i][1] = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 波形データをロード (Load waveform data)
|
||
signed char wave_data[100][0x100];
|
||
|
||
BOOL InitWaveData100(void)
|
||
{
|
||
HRSRC hrscr;
|
||
DWORD *lpdword; // リソースのアドレス (Resource address)
|
||
|
||
if (lpDS == NULL)
|
||
return FALSE;
|
||
|
||
// リソースの検索 (Search for resources)
|
||
hrscr = FindResourceA(NULL, "WAVE100", "WAVE");
|
||
|
||
if (hrscr == NULL)
|
||
return FALSE;
|
||
|
||
// リソースのアドレスを取得 (Get resource address)
|
||
lpdword = (DWORD*)LockResource(LoadResource(NULL, hrscr));
|
||
memcpy(wave_data, lpdword, 100 * 0x100);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
// 波形を100個の中から選択して作成 (Select from 100 waveforms to create)
|
||
BOOL MakeOrganyaWave(signed char track, signed char wave_no, signed char pipi)
|
||
{
|
||
if (lpDS == NULL)
|
||
return FALSE;
|
||
|
||
if (wave_no > 99)
|
||
return FALSE;
|
||
|
||
ReleaseOrganyaObject(track);
|
||
MakeSoundObject8(wave_data[wave_no], track, pipi);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/////////////////////////////////////////////
|
||
//■オルガーニャドラムス■■■■■■■■/////// (Organya drums)
|
||
/////////////////////
|
||
|
||
void ChangeDramFrequency(unsigned char key, signed char track)
|
||
{
|
||
if (lpDS == NULL)
|
||
return;
|
||
|
||
lpSECONDARYBUFFER[150 + track]->SetFrequency(key * 800 + 100);
|
||
}
|
||
|
||
void ChangeDramPan(unsigned char pan, signed char track)
|
||
{
|
||
if (lpDS == NULL)
|
||
return;
|
||
|
||
lpSECONDARYBUFFER[150 + track]->SetPan((pan_tbl[pan] - 0x100) * 10);
|
||
}
|
||
|
||
void ChangeDramVolume(long volume, signed char track)
|
||
{
|
||
if (lpDS == NULL)
|
||
return;
|
||
|
||
lpSECONDARYBUFFER[150 + track]->SetVolume((volume - 0xFF) * 8);
|
||
}
|
||
|
||
// サウンドの再生 (Play sound)
|
||
void PlayDramObject(unsigned char key, int mode, signed char track)
|
||
{
|
||
if (lpDS == NULL)
|
||
return;
|
||
|
||
if (lpSECONDARYBUFFER[150 + track] != NULL)
|
||
{
|
||
switch (mode)
|
||
{
|
||
case 0: // 停止 (Stop)
|
||
lpSECONDARYBUFFER[150 + track]->Stop();
|
||
lpSECONDARYBUFFER[150 + track]->SetCurrentPosition(0);
|
||
break;
|
||
|
||
case 1: // 再生 (Playback)
|
||
lpSECONDARYBUFFER[150 + track]->Stop();
|
||
lpSECONDARYBUFFER[150 + track]->SetCurrentPosition(0);
|
||
ChangeDramFrequency(key, track); // 周波数を設定して (Set the frequency)
|
||
lpSECONDARYBUFFER[150 + track]->Play(0, 0, 0);
|
||
break;
|
||
|
||
case 2: // 歩かせ停止 (Stop playback)
|
||
break;
|
||
|
||
case -1:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
ORGDATA org_data;
|
||
|
||
OrgData::OrgData(void)
|
||
{
|
||
for (int i = 0; i < MAXTRACK; i++)
|
||
{
|
||
info.tdata[i].note_list = NULL;
|
||
info.tdata[i].note_p = NULL;
|
||
}
|
||
}
|
||
|
||
void OrgData::InitOrgData(void)
|
||
{
|
||
track = 0;
|
||
info.alloc_note = ALLOCNOTE; // とりあえず10000個確保 (For the time being, secure 10,000 pieces)
|
||
info.dot = 4;
|
||
info.line = 4;
|
||
info.wait = 128;
|
||
info.repeat_x = info.dot * info.line * 0;
|
||
info.end_x = info.dot * info.line * 255;
|
||
|
||
for (int i = 0; i < MAXTRACK; i++)
|
||
{
|
||
info.tdata[i].freq = 1000;
|
||
info.tdata[i].wave_no = 0;
|
||
info.tdata[i].pipi = 0;
|
||
}
|
||
|
||
NoteAlloc(info.alloc_note);
|
||
SetMusicInfo(&info, SETALL);
|
||
|
||
def_pan = DEFPAN;
|
||
def_volume = DEFVOLUME;
|
||
}
|
||
|
||
// 曲情報を設定。flagはアイテムを指定 (Set song information. flag specifies an item)
|
||
BOOL OrgData::SetMusicInfo(MUSICINFO *mi, unsigned long flag)
|
||
{
|
||
char str[32]; // Leftover debug junk
|
||
int i;
|
||
|
||
if (flag & SETGRID) // グリッドを有効に (Enable grid)
|
||
{
|
||
info.dot = mi->dot;
|
||
info.line = mi->line;
|
||
}
|
||
|
||
if (flag & SETWAIT)
|
||
{
|
||
info.wait = mi->wait;
|
||
itoa(mi->wait, str, 10); // Leftover debug junk
|
||
}
|
||
|
||
if (flag & SETREPEAT)
|
||
{
|
||
info.repeat_x = mi->repeat_x;
|
||
info.end_x = mi->end_x;
|
||
}
|
||
|
||
if (flag & SETFREQ)
|
||
{
|
||
for (i = 0; i < MAXMELODY; i++)
|
||
{
|
||
info.tdata[i].freq = mi->tdata[i].freq;
|
||
info.tdata[i].pipi = info.tdata[i].pipi; // Just sets info.tdata[i].pipi to itself (SETPIPI already sets pipi, so maybe this line shouldn't be here in the first place)
|
||
}
|
||
}
|
||
|
||
if (flag & SETWAVE)
|
||
for (i = 0; i < MAXTRACK; i++)
|
||
info.tdata[i].wave_no = mi->tdata[i].wave_no;
|
||
|
||
if (flag & SETPIPI)
|
||
for (i = 0; i < MAXTRACK; i++)
|
||
info.tdata[i].pipi = mi->tdata[i].pipi;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
// 指定の数だけNoteDataの領域を確保(初期化) (Allocate the specified number of NoteData areas (initialization))
|
||
BOOL OrgData::NoteAlloc(unsigned short alloc)
|
||
{
|
||
int i,j;
|
||
|
||
for (j = 0; j < MAXTRACK; j++)
|
||
{
|
||
info.tdata[j].wave_no = 0;
|
||
info.tdata[j].note_list = NULL; // コンストラクタにやらせたい (I want the constructor to do it)
|
||
info.tdata[j].note_p = (NOTELIST*)malloc(sizeof(NOTELIST) * alloc);
|
||
|
||
if (info.tdata[j].note_p == NULL)
|
||
{
|
||
for (i = 0; i < MAXTRACK; i++)
|
||
{
|
||
if (info.tdata[i].note_p != NULL)
|
||
{
|
||
free(info.tdata[i].note_p);
|
||
#ifdef FIX_BUGS
|
||
info.tdata[i].note_p = NULL;
|
||
#else
|
||
info.tdata[j].note_p = NULL; // Uses j instead of i
|
||
#endif
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
for (i = 0; i < alloc; i++)
|
||
{
|
||
(info.tdata[j].note_p + i)->from = NULL;
|
||
(info.tdata[j].note_p + i)->to = NULL;
|
||
(info.tdata[j].note_p + i)->length = 0;
|
||
(info.tdata[j].note_p + i)->pan = PANDUMMY;
|
||
(info.tdata[j].note_p + i)->volume = VOLDUMMY;
|
||
(info.tdata[j].note_p + i)->y = KEYDUMMY;
|
||
}
|
||
}
|
||
|
||
for (j = 0; j < MAXMELODY; j++)
|
||
MakeOrganyaWave(j, info.tdata[j].wave_no, info.tdata[j].pipi);
|
||
|
||
track = 0; // 今はここに書いておく (Write here now)
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
// NoteDataを開放 (Release NoteData)
|
||
void OrgData::ReleaseNote(void)
|
||
{
|
||
for (int i = 0; i < MAXTRACK; i++)
|
||
{
|
||
if (info.tdata[i].note_p != NULL)
|
||
{
|
||
free(info.tdata[i].note_p);
|
||
info.tdata[i].note_p = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
char pass[7] = "Org-01";
|
||
char pass2[7] = "Org-02"; // Pipi
|
||
|
||
BOOL OrgData::InitMusicData(const char *path)
|
||
{
|
||
ORGANYADATA org_data;
|
||
NOTELIST *np;
|
||
int i,j;
|
||
char pass_check[6];
|
||
char ver = 0;
|
||
|
||
HRSRC hrscr = FindResourceA(NULL, path, "ORG");
|
||
if (hrscr == NULL)
|
||
return FALSE;
|
||
|
||
unsigned char *p = (unsigned char*)LockResource(LoadResource(0, hrscr));
|
||
|
||
memcpy(&pass_check[0], p, 6);
|
||
p += 6;
|
||
|
||
if(memcmp(pass_check, pass, 6) == 0)
|
||
ver = 1;
|
||
if(memcmp(pass_check, pass2, 6) == 0)
|
||
ver = 2;
|
||
|
||
if(ver == 0)
|
||
return FALSE;
|
||
|
||
// 曲情報の読み込み (Loading song information)
|
||
memcpy(&org_data, p, sizeof(ORGANYADATA));
|
||
p += sizeof(ORGANYADATA);
|
||
|
||
// 曲の情報を設定 (Set song information)
|
||
info.wait = org_data.wait;
|
||
info.line = org_data.line;
|
||
info.dot = org_data.dot;
|
||
info.repeat_x = org_data.repeat_x;
|
||
info.end_x = org_data.end_x;
|
||
|
||
for (i = 0; i < MAXTRACK; i++)
|
||
{
|
||
info.tdata[i].freq = org_data.tdata[i].freq;
|
||
|
||
if (ver == 1)
|
||
info.tdata[i].pipi = 0;
|
||
else
|
||
info.tdata[i].pipi = org_data.tdata[i].pipi;
|
||
|
||
info.tdata[i].wave_no = org_data.tdata[i].wave_no;
|
||
}
|
||
|
||
// 音符のロード (Loading notes)
|
||
for (j = 0; j < MAXTRACK; j++)
|
||
{
|
||
// 最初の音符はfromがNULLとなる (The first note has from as NULL)
|
||
if (org_data.tdata[j].note_num == 0)
|
||
{
|
||
info.tdata[j].note_list = NULL;
|
||
continue;
|
||
}
|
||
|
||
// リストを作る (Make a list)
|
||
np = info.tdata[j].note_p;
|
||
info.tdata[j].note_list = info.tdata[j].note_p;
|
||
np->from = NULL;
|
||
np->to = (np + 1);
|
||
np++;
|
||
|
||
for (i = 1; i < org_data.tdata[j].note_num; i++)
|
||
{
|
||
np->from = (np - 1);
|
||
np->to = (np + 1);
|
||
np++;
|
||
}
|
||
|
||
// 最後の音符のtoはNULL (The last note to is NULL)
|
||
np--;
|
||
np->to = NULL;
|
||
|
||
// 内容を代入 (Assign content)
|
||
np = info.tdata[j].note_p; // X座標 (X coordinate)
|
||
for (i = 0; i < org_data.tdata[j].note_num; i++)
|
||
{
|
||
memcpy(&np->x, p, sizeof(long));
|
||
p += sizeof(long);
|
||
np++;
|
||
}
|
||
|
||
np = info.tdata[j].note_p; // Y座標 (Y coordinate)
|
||
for (i = 0; i < org_data.tdata[j].note_num; i++)
|
||
{
|
||
memcpy(&np->y, p, sizeof(unsigned char));
|
||
p += sizeof(unsigned char);
|
||
np++;
|
||
}
|
||
|
||
np = info.tdata[j].note_p; // 長さ (Length)
|
||
for (i = 0; i < org_data.tdata[j].note_num; i++)
|
||
{
|
||
memcpy(&np->length, p, sizeof(unsigned char));
|
||
p += sizeof(unsigned char);
|
||
np++;
|
||
}
|
||
|
||
np = info.tdata[j].note_p; // ボリューム (Volume)
|
||
for (i = 0; i < org_data.tdata[j].note_num; i++)
|
||
{
|
||
memcpy(&np->volume, p, sizeof(unsigned char));
|
||
p += sizeof(unsigned char);
|
||
np++;
|
||
}
|
||
|
||
np = info.tdata[j].note_p; // パン (Pan)
|
||
for (i = 0; i < org_data.tdata[j].note_num; i++)
|
||
{
|
||
memcpy(&np->pan, p, sizeof(unsigned char));
|
||
p += sizeof(unsigned char);
|
||
np++;
|
||
}
|
||
}
|
||
|
||
// データを有効に (Enable data)
|
||
for (j = 0; j < MAXMELODY; j++)
|
||
MakeOrganyaWave(j,info.tdata[j].wave_no, info.tdata[j].pipi);
|
||
|
||
// Pixel ripped out some code so he could use PixTone sounds as drums, but he left this dead code
|
||
for (j = MAXMELODY; j < MAXTRACK; j++)
|
||
{
|
||
i = info.tdata[j].wave_no;
|
||
//InitDramObject(dram_name[i], j - MAXMELODY);
|
||
}
|
||
|
||
SetPlayPointer(0); // 頭出し (Cue)
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
// 曲情報を取得 (Get song information)
|
||
void OrgData::GetMusicInfo(MUSICINFO *mi)
|
||
{
|
||
mi->dot = info.dot;
|
||
mi->line = info.line;
|
||
mi->alloc_note = info.alloc_note;
|
||
mi->wait = info.wait;
|
||
mi->repeat_x = info.repeat_x;
|
||
mi->end_x = info.end_x;
|
||
|
||
for (int i = 0; i < MAXTRACK; i++)
|
||
{
|
||
mi->tdata[i].freq = info.tdata[i].freq;
|
||
mi->tdata[i].wave_no = info.tdata[i].wave_no;
|
||
mi->tdata[i].pipi = info.tdata[i].pipi;
|
||
}
|
||
}
|
||
|
||
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
|
||
//プロトタイプ宣言 (prototype declaration)
|
||
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
|
||
|
||
BOOL InitMMTimer();
|
||
BOOL StartTimer(DWORD dwTimer);
|
||
//VOID CALLBACK TimerProc(UINT uTID,UINT uMsg,DWORD dwUser,DWORD dwParam1,DWORD dwParam2); // The original code used the wrong types
|
||
VOID CALLBACK TimerProc(UINT uTID,UINT uMsg,DWORD_PTR dwUser,DWORD_PTR dwParam1,DWORD_PTR dwParam2);
|
||
BOOL QuitMMTimer();
|
||
|
||
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
|
||
//グローバル変数 (Global variable)
|
||
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
|
||
UINT ExactTime = 13; // 最小精度 (Minimum accuracy)
|
||
UINT TimerID;
|
||
BOOL bTimer;
|
||
|
||
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
|
||
// タイマー精度を設定する。 (Set timer accuracy.)
|
||
// この関数はアプリケーション初期化時に一度呼び出す。 (This function is called once when the application is initialized.)
|
||
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
|
||
BOOL InitMMTimer(void)
|
||
{
|
||
TIMECAPS tc;
|
||
MMRESULT ret;
|
||
|
||
// タイマーの精度情報を取得する (Get timer accuracy information)
|
||
ret = timeGetDevCaps(&tc,sizeof(TIMECAPS));
|
||
if (ret != TIMERR_NOERROR)
|
||
return FALSE;
|
||
|
||
if (ExactTime < tc.wPeriodMin)
|
||
ExactTime = tc.wPeriodMin;
|
||
|
||
// この精度で初期化する (Initialize with this precision)
|
||
ret = timeBeginPeriod(ExactTime);
|
||
if (ret != TIMERR_NOERROR)
|
||
return FALSE;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
|
||
// タイマーを起動する。 (Start the timer.)
|
||
// dwTimer 設定するタイマー間隔 (dwTimer Timer interval to be set)
|
||
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
|
||
BOOL StartTimer(DWORD dwTimer)
|
||
{
|
||
MMRESULT ret = MMSYSERR_NOERROR;
|
||
ExactTime = dwTimer;
|
||
|
||
// タイマーを生成する (Generate timer)
|
||
TimerID = timeSetEvent
|
||
(
|
||
dwTimer, // タイマー時間 (Timer time)
|
||
10, // 許容できるタイマー精度 (Acceptable timer accuracy)
|
||
TimerProc, // コールバックプロシージャ (Callback procedure)
|
||
0, // ユーザーがコールバック関数のdwUserに送る情報値 (Information value sent by user to dwUser in callback function)
|
||
TIME_PERIODIC // タイマー時間毎にイベントを発生させる (Generate an event every timer time)
|
||
);
|
||
|
||
if (ret != TIMERR_NOERROR)
|
||
return FALSE;
|
||
|
||
bTimer = TRUE;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
|
||
// タイマーのコールバック関数 (Timer callback function)
|
||
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
|
||
//VOID CALLBACK TimerProc(UINT uTID,UINT uMsg,DWORD dwUser,DWORD dwParam1,DWORD dwParam2) // The original code used the wrong types
|
||
VOID CALLBACK TimerProc(UINT uTID,UINT uMsg,DWORD_PTR dwUser,DWORD_PTR dwParam1,DWORD_PTR dwParam2)
|
||
{
|
||
(void)uTID;
|
||
(void)uMsg;
|
||
(void)dwUser;
|
||
(void)dwParam1;
|
||
(void)dwParam2;
|
||
|
||
DWORD dwNowTime;
|
||
dwNowTime = timeGetTime();
|
||
//===================================================================================
|
||
// ここにユーザー定義のソースを書く。 (Write user-defined source here.)
|
||
// 基本的に関数を呼び出すだけで処理は他の関数でするべきだろう。 (Basically just call a function and the process should be another function.)
|
||
//===================================================================================
|
||
org_data.PlayData();
|
||
}
|
||
|
||
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
|
||
// タイマーリソースを開放する。 (Release timer resources.)
|
||
// アプリケーション終了時に一度呼び出す。 (Call once when the application ends.)
|
||
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
|
||
BOOL QuitMMTimer(void)
|
||
{
|
||
MMRESULT ret;
|
||
|
||
if (!bTimer)
|
||
return FALSE;
|
||
|
||
if(TimerID != TIMERR_NOERROR)
|
||
{
|
||
// タイマーを使用中なら終了させる (Terminate timer if in use)
|
||
ret = timeKillEvent(TimerID);
|
||
if (ret != TIMERR_NOERROR)
|
||
return FALSE;
|
||
}
|
||
|
||
// タイマーリソースを開放する (Release timer resources)
|
||
ret = timeEndPeriod(ExactTime);
|
||
if (ret != TIMERR_NOERROR)
|
||
return FALSE;
|
||
|
||
bTimer = FALSE;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
// Play data
|
||
long PlayPos; // Called 'play_p' in the source code release
|
||
NOTELIST *np[MAXTRACK];
|
||
long now_leng[MAXMELODY];
|
||
|
||
int Volume = 100;
|
||
int TrackVol[MAXTRACK];
|
||
BOOL bFadeout = FALSE;
|
||
|
||
void OrgData::PlayData(void)
|
||
{
|
||
int i;
|
||
|
||
// Handle fading out
|
||
if (bFadeout && Volume)
|
||
Volume -= 2;
|
||
if (Volume < 0)
|
||
Volume = 0;
|
||
|
||
// メロディの再生 (Play melody)
|
||
for (i = 0; i < MAXMELODY; i++)
|
||
{
|
||
if (np[i] != NULL && PlayPos == np[i]->x)
|
||
{
|
||
if (!g_mute[i] && np[i]->y != KEYDUMMY) // 音が来た。 (The sound has come.)
|
||
{
|
||
PlayOrganObject(np[i]->y, -1, i, info.tdata[i].freq);
|
||
now_leng[i] = np[i]->length;
|
||
}
|
||
|
||
if (np[i]->pan != PANDUMMY)
|
||
ChangeOrganPan(np[i]->y, np[i]->pan, i);
|
||
if (np[i]->volume != VOLDUMMY)
|
||
TrackVol[i] = np[i]->volume;
|
||
|
||
np[i] = np[i]->to; // 次の音符を指す (Points to the next note)
|
||
}
|
||
|
||
if (now_leng[i] == 0)
|
||
PlayOrganObject(0, 2, i, info.tdata[i].freq);
|
||
|
||
if (now_leng[i] > 0)
|
||
now_leng[i]--;
|
||
|
||
if (np[i])
|
||
ChangeOrganVolume(np[i]->y, TrackVol[i] * Volume / 0x7F, i);
|
||
}
|
||
|
||
// ドラムの再生 (Drum playback)
|
||
for (i = MAXMELODY; i < MAXTRACK; i++)
|
||
{
|
||
if (np[i] != NULL && PlayPos == np[i]->x) // 音が来た。 (The sound has come.)
|
||
{
|
||
if (np[i]->y != KEYDUMMY && !g_mute[i]) // ならす (Tame)
|
||
PlayDramObject(np[i]->y, 1, i - MAXMELODY);
|
||
|
||
if (np[i]->pan != PANDUMMY)
|
||
ChangeDramPan(np[i]->pan, i - MAXMELODY);
|
||
if (np[i]->volume != VOLDUMMY)
|
||
TrackVol[i] = np[i]->volume;
|
||
|
||
np[i] = np[i]->to; // 次の音符を指す (Points to the next note)
|
||
}
|
||
|
||
if (np[i])
|
||
ChangeDramVolume(TrackVol[i] * Volume / 0x7F, i - MAXMELODY);
|
||
}
|
||
|
||
// Looping
|
||
PlayPos++;
|
||
if (PlayPos >= info.end_x)
|
||
{
|
||
PlayPos = info.repeat_x;
|
||
SetPlayPointer(PlayPos);
|
||
}
|
||
}
|
||
|
||
void OrgData::SetPlayPointer(long x)
|
||
{
|
||
for (int i = 0; i < MAXTRACK; i++)
|
||
{
|
||
np[i] = info.tdata[i].note_list;
|
||
while (np[i] != NULL && np[i]->x < x)
|
||
np[i] = np[i]->to; // 見るべき音符を設定 (Set note to watch)
|
||
}
|
||
|
||
PlayPos = x;
|
||
}
|
||
|
||
// Start and end organya
|
||
BOOL StartOrganya(LPDIRECTSOUND _lpDS, const char *path_wave) // Both arguments are ignored for some reason
|
||
{
|
||
if (lpDS == NULL)
|
||
return FALSE;
|
||
|
||
if (!InitWaveData100())
|
||
return FALSE;
|
||
|
||
org_data.InitOrgData();
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
// Load organya file
|
||
BOOL LoadOrganya(const char *name)
|
||
{
|
||
if (lpDS == NULL)
|
||
return FALSE;
|
||
|
||
if (!org_data.InitMusicData(name))
|
||
return FALSE;
|
||
|
||
Volume = 100;
|
||
bFadeout = 0;
|
||
|
||
#ifdef FIX_BUGS
|
||
return TRUE;
|
||
#else
|
||
return FALSE; // Err... isn't this meant to be 'TRUE'?
|
||
#endif
|
||
}
|
||
|
||
void SetOrganyaPosition(unsigned int x)
|
||
{
|
||
if (lpDS == NULL)
|
||
return;
|
||
|
||
org_data.SetPlayPointer(x);
|
||
Volume = 100;
|
||
bFadeout = FALSE;
|
||
}
|
||
|
||
unsigned int GetOrganyaPosition(void)
|
||
{
|
||
if (lpDS == NULL)
|
||
return 0;
|
||
|
||
return PlayPos;
|
||
}
|
||
|
||
void PlayOrganyaMusic(void)
|
||
{
|
||
if (lpDS == NULL)
|
||
return;
|
||
|
||
QuitMMTimer();
|
||
InitMMTimer();
|
||
StartTimer(org_data.info.wait);
|
||
}
|
||
|
||
BOOL ChangeOrganyaVolume(signed int volume)
|
||
{
|
||
if (lpDS == NULL)
|
||
return FALSE;
|
||
|
||
if (volume < 0 || volume > 100)
|
||
return FALSE;
|
||
|
||
Volume = volume;
|
||
return TRUE;
|
||
}
|
||
|
||
void StopOrganyaMusic(void)
|
||
{
|
||
if (lpDS == NULL)
|
||
return;
|
||
|
||
// Stop timer
|
||
QuitMMTimer();
|
||
|
||
// Stop notes
|
||
for (int i = 0; i < MAXMELODY; i++)
|
||
PlayOrganObject(0, 2, i, 0);
|
||
|
||
memset(old_key, 255, sizeof(old_key));
|
||
memset(key_on, 0, sizeof(key_on));
|
||
memset(key_twin, 0, sizeof(key_twin));
|
||
|
||
Sleep(100);
|
||
}
|
||
|
||
void SetOrganyaFadeout(void)
|
||
{
|
||
bFadeout = TRUE;
|
||
}
|
||
|
||
void EndOrganya(void)
|
||
{
|
||
if (lpDS == NULL)
|
||
return;
|
||
|
||
// End timer
|
||
QuitMMTimer();
|
||
|
||
// Release everything related to org
|
||
org_data.ReleaseNote();
|
||
|
||
for (int i = 0; i < MAXMELODY; i++)
|
||
{
|
||
PlayOrganObject(0, 0, i, 0);
|
||
ReleaseOrganyaObject(i);
|
||
}
|
||
}
|