ref: 470c5d86d5ec428c8c372e9050c707d7cba369e6
parent: e67c1e3640260d7797909e8b724b4b5eceb9739e
author: Clownacy <Clownacy@users.noreply.github.com>
date: Wed Aug 28 03:55:42 EDT 2019
ASM-accurate Sound.cpp and Organya.cpp (except for one function)
--- a/msvc2003/CSE2.vcproj
+++ b/msvc2003/CSE2.vcproj
@@ -34,7 +34,7 @@
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="SDL2/lib/SDL2.lib SDL2/lib/SDL2main.lib freetype/lib/freetype.lib Version.lib"
+ AdditionalDependencies="SDL2/lib/SDL2.lib SDL2/lib/SDL2main.lib freetype/lib/freetype.lib Version.lib DSound.lib WinMM.lib"
OutputFile="$(OutDir)\$(ProjectName).exe"
LinkIncremental="2"
AdditionalLibraryDirectories=""
@@ -85,7 +85,7 @@
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="SDL2/lib/SDL2.lib SDL2/lib/SDL2main.lib freetype/lib/freetype.lib Version.lib"
+ AdditionalDependencies="SDL2/lib/SDL2.lib SDL2/lib/SDL2main.lib freetype/lib/freetype.lib Version.lib DSound.lib WinMM.lib"
OutputFile="$(OutDir)\$(ProjectName).exe"
LinkIncremental="1"
IgnoreAllDefaultLibraries="FALSE"
@@ -135,7 +135,7 @@
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="SDL2/lib/SDL2.lib SDL2/lib/SDL2main.lib freetype/lib/freetype.lib Version.lib"
+ AdditionalDependencies="SDL2/lib/SDL2.lib SDL2/lib/SDL2main.lib freetype/lib/freetype.lib Version.lib DSound.lib WinMM.lib"
OutputFile="$(OutDir)\$(ProjectName).exe"
LinkIncremental="1"
IgnoreAllDefaultLibraries="FALSE"
@@ -186,7 +186,7 @@
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="SDL2/lib/SDL2.lib SDL2/lib/SDL2main.lib freetype/lib/freetype.lib Version.lib"
+ AdditionalDependencies="SDL2/lib/SDL2.lib SDL2/lib/SDL2main.lib freetype/lib/freetype.lib Version.lib DSound.lib WinMM.lib"
OutputFile="$(OutDir)\$(ProjectName).exe"
LinkIncremental="2"
AdditionalLibraryDirectories=""
--- a/msvc2003/devilution/comparer-config.toml
+++ b/msvc2003/devilution/comparer-config.toml
@@ -964,6 +964,10 @@
addr = 0x41A7C0
[[func]]
+name = "MakeSoundObject8"
+addr = 0x41A8F0
+
+[[func]]
name = "ChangeOrganFrequency"
addr = 0x41ABA0
size = 0xC9
@@ -983,7 +987,7 @@
addr = 0x41ADC0
[[func]]
-name = "ReleaseOrganya"
+name = "ReleaseOrganyaObject"
addr = 0x41B2A0
[[func]]
@@ -1011,6 +1015,95 @@
addr = 0x41B510
[[func]]
+name = "OrgData::OrgData"
+addr = 0x41B600
+
+[[func]]
+name = "OrgData::InitOrgData"
+addr = 0x41B650
+
+[[func]]
+name = "OrgData::SetMusicInfo"
+addr = 0x41B730
+
+[[func]]
+name = "OrgData::NoteAlloc"
+addr = 0x41B890
+
+[[func]]
+name = "OrgData::ReleaseNote"
+addr = 0x41BA70
+
+[[func]]
+name = "OrgData::InitMusicData"
+addr = 0x41BAD0
+
+[[func]]
+name = "OrgData::GetMusicInfo"
+addr = 0x41C0B0
+
+[[func]]
+name = "InitMMTimer"
+addr = 0x41C180
+
+[[func]]
+name = "StartTimer"
+addr = 0x41C1E0
+size = 0x4A
+
+[[func]]
+name = "TimerProc"
+addr = 0x41C230
+
+[[func]]
+name = "QuitMMTimer"
+addr = 0x41C250
+
+[[func]]
+name = "OrgData::PlayData"
+addr = 0x41C2B0
+
+[[func]]
+name = "OrgData::SetPlayPointer"
+addr = 0x41C630
+
+[[func]]
+name = "StartOrganya"
+addr = 0x41C6C0
+
+[[func]]
+name = "LoadOrganya"
+addr = 0x41C6F0
+
+[[func]]
+name = "SetOrganyaPosition"
+addr = 0x41C730
+
+[[func]]
+name = "GetOrganyaPosition"
+addr = 0x41C770
+
+[[func]]
+name = "PlayOrganyaMusic"
+addr = 0x41C790
+
+[[func]]
+name = "ChangeOrganyaVolume"
+addr = 0x41C7C0
+
+[[func]]
+name = "StopOrganyaMusic"
+addr = 0x41C7F0
+
+[[func]]
+name = "SetOrganyaFadeout"
+addr = 0x41C880
+
+[[func]]
+name = "EndOrganya"
+addr = 0x41C890
+
+[[func]]
name = "MakeWaveTables"
addr = 0x41C8F0
@@ -1107,6 +1200,22 @@
addr = 0x41FE70
[[func]]
+name = "InitDirectSound"
+addr = 0x4200C0
+
+[[func]]
+name = "EndDirectSound"
+addr = 0x4201A0
+
+[[func]]
+name = "InitSoundObject"
+addr = 0x420240
+
+[[func]]
+name = "LoadSoundObject"
+addr = 0x420390
+
+[[func]]
name = "PlaySoundObject"
addr = 0x420640
@@ -1124,6 +1233,10 @@
name = "ChangeSoundPan"
addr = 0x4207A0
size = 0x36
+
+[[func]]
+name = "MakePixToneObject"
+addr = 0x4207E0
[[func]]
name = "TransferStage"
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -5,6 +5,7 @@
#include <string.h>
#include "SDL.h"
+#include "SDL_syswm.h"
#include "WindowsWrapper.h"
@@ -347,11 +348,16 @@
CortBox(&clip_rect, 0x000000);
PutBitmap3(&clip_rect, (WINDOW_WIDTH - 64) / 2, (WINDOW_HEIGHT - 8) / 2, &loading_rect, SURFACE_ID_LOADING);
+ SDL_SysWMinfo wmInfo;
+ SDL_VERSION(&wmInfo.version);
+ SDL_GetWindowWMInfo(gWindow, &wmInfo);
+ ghWnd = wmInfo.info.win.window;
+
// Draw to screen
if (Flip_SystemTask(ghWnd))
{
// Initialize sound
- InitDirectSound();
+ InitDirectSound(ghWnd);
// Initialize joystick
if (config.bJoystick && InitDirectInput())
--- a/src/Organya.cpp
+++ b/src/Organya.cpp
@@ -10,6 +10,8 @@
#include <stdio.h>
#include <string.h>
+#include <dsound.h>
+
#include "SDL.h"
#include "WindowsWrapper.h"
@@ -24,74 +26,112 @@
#define MAXMELODY 8
#define MAXDRAM 8
-SOUNDBUFFER *lpORGANBUFFER[8][8][2] = {NULL};
-SOUNDBUFFER **lpDRAMBUFFER = &lpSECONDARYBUFFER[0x96];
+#define ALLOCNOTE 4096
-MUSICINFO info;
+#define DEFVOLUME 200//255はVOLDUMMY。MAXは254
+#define DEFPAN 6
-int gTrackVol[MAXTRACK];
-int gOrgVolume = 100;
-BOOL bFadeout = FALSE;
+//曲情報をセットする時のフラグ
+#define SETALL 0xffffffff//全てをセット
+#define SETWAIT 0x00000001
+#define SETGRID 0x00000002
+#define SETALLOC 0x00000004
+#define SETREPEAT 0x00000008
+#define SETFREQ 0x00000010
+#define SETWAVE 0x00000020
+#define SETPIPI 0x00000040
-BOOL OrganyaNoteAlloc(unsigned short alloc)
+typedef struct ORGANYATRACK
{
- for (int j = 0; j < MAXTRACK; j++)
- {
- info.tdata[j].wave_no = 0;
- info.tdata[j].note_list = NULL;
- info.tdata[j].note_p = new NOTELIST[alloc];
+ 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;
- if (info.tdata[j].note_p == NULL)
- {
- for (int i = 0; i < MAXTRACK; i++)
- {
- if (info.tdata[i].note_p != NULL)
- {
- delete[] info.tdata[i].note_p;
- info.tdata[j].note_p = NULL; // Uses j instead of i
- }
- }
+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;
- return FALSE;
- }
+// Below are Organya song data structures
+typedef struct NOTELIST
+{
+ NOTELIST *from; // Previous address
+ NOTELIST *to; // Next address
- for (int 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;
- }
- }
+ long x; // Position
+ unsigned char length; // Sound length
+ unsigned char y; // Sound height
+ unsigned char volume; // Volume
+ unsigned char pan;
+} NOTELIST;
- for (int j = 0; j < MAXMELODY; j++)
- MakeOrganyaWave(j, info.tdata[j].wave_no, info.tdata[j].pipi);
- // for(int j = 0; j < MAXDRAM; j++)
- // InitDramObject(j);
+// Track data * 8
+typedef struct TRACKDATA
+{
+ unsigned short freq; // Frequency (1000 is default)
+ unsigned char wave_no; // Waveform No.
+ signed char pipi;
- // this->track = 0;
+ NOTELIST *note_p;
+ NOTELIST *note_list;
+} TRACKDATA;
- return FALSE;
-}
+// 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[16];
+} MUSICINFO;
-void OrganyaReleaseNote()
+// メインクラス。このアプリケーションの中心。(クラスってやつを初めて使う) (Main class. The heart of this application. (Class is used for the first time))
+typedef struct OrgData
{
- for (int i = 0; i < MAXTRACK; i++)
- {
- if (info.tdata[i].note_p != NULL)
- {
-#ifdef FIX_BUGS
- delete[] info.tdata[i].note_p;
-#else
- delete info.tdata[i].note_p; // Should be delete[]
-#endif
- info.tdata[i].note_p = NULL;
- }
- }
-}
+ 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 OrgData::InitMusicData(const char *path);
+} ORGDATA;
+ORGDATA org_data;
+
+LPDIRECTSOUNDBUFFER lpORGANBUFFER[8][8][2] = {NULL};
+
+int gTrackVol[MAXTRACK];
+int gOrgVolume = 100;
+BOOL bFadeout = FALSE;
+BOOL g_mute[MAXTRACK]; // Used by the debug Mute menu
+
+
+/////////////////////////////////////////////
+//■オルガーニャ■■■■■■■■■■■■/////// (Organya)
+/////////////////////
+
// Wave playing and loading
typedef struct
{
@@ -100,7 +140,7 @@
short oct_size;
} OCTWAVE;
-OCTWAVE oct_wave[8] =
+static const OCTWAVE oct_wave[8] =
{
{ 256, 1, 4 }, // 0 Oct
{ 256, 2, 8 }, // 1 Oct
@@ -112,44 +152,89 @@
{ 8,128, 32 }, // 7 Oct
};
+static 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)
{
- for (int j = 0; j < 8; j++)
+ 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 (int k = 0; k < 2; k++)
+ for (k = 0; k < 2; k++)
{
- size_t wave_size = oct_wave[j].wave_size;
- size_t data_size = pipi ? wave_size * oct_wave[j].oct_size : wave_size;
+ wave_size = oct_wave[j].wave_size;
- // Create sound buffer
- lpORGANBUFFER[track][j][k] = new SOUNDBUFFER(data_size);
+ if (pipi)
+ data_size = wave_size * oct_wave[j].oct_size;
+ else
+ data_size = wave_size;
+ ZeroMemory(&dsbd, sizeof(DSBUFFERDESC));
+
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ 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
- unsigned char *wp = new unsigned char[data_size];
- unsigned char *wp_sub = wp;
- size_t wav_tp = 0;
+ wp = (BYTE*)malloc(data_size);
+ wp_sub = wp;
+ wav_tp = 0;
- for (size_t i = 0; i < data_size; i++)
+ for (i = 0; i < data_size; i++)
{
- unsigned char work = *(wavep + wav_tp);
+ work = *(wavep + wav_tp);
work += 0x80;
- *wp_sub = work;
+ *wp_sub = (BYTE)work;
wav_tp += 0x100 / wave_size;
- if (wav_tp >= 0x100)
+ if (wav_tp > 0xFF)
wav_tp -= 0x100;
wp_sub++;
}
- // Copy wave data to sound buffer
- unsigned char *buf;
- lpORGANBUFFER[track][j][k]->Lock(&buf, NULL);
- memcpy(buf, wp, data_size);
- lpORGANBUFFER[track][j][k]->Unlock();
+ // データの転送 (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);
- delete[] wp;
+ free(wp);
}
}
@@ -156,44 +241,52 @@
return TRUE;
}
-// Playing melody tracks
-short freq_tbl[12] = {262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494};
+static const 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));
- }
- }
+ 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 + α)
}
-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};
-unsigned char key_on[MAXTRACK] = {0};
-unsigned char key_twin[MAXTRACK] = {0};
+const 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)
+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)
+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:
+ case 0: // 停止 (Stop)
if (old_key[track] != 0xFF)
{
lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Stop();
@@ -201,51 +294,56 @@
}
break;
- case 1:
+ case 1: // 再生 (Playback)
break;
- case 2:
+ case 2: // 歩かせ停止 (Stop playback)
if (old_key[track] != 0xFF)
{
- lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Play(false);
+ 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)
+ if (old_key[track] == 0xFF) // 新規鳴らす (New sound)
{
- ChangeOrganFrequency(key % 12, track, freq);
- lpORGANBUFFER[track][key / 12][key_twin[track]]->Play(true);
+ 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)
+ else if (key_on[track] == 1 && old_key[track] == key) // 同じ音 (Same sound)
{
- lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Play(false);
+ // 今なっているのを歩かせ停止 (Stop playback now)
+ lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Play(0, 0, 0);
key_twin[track]++;
- if (key_twin[track] == 2)
+ if (key_twin[track] > 1)
key_twin[track] = 0;
- lpORGANBUFFER[track][key / 12][key_twin[track]]->Play(true);
+ lpORGANBUFFER[track][key / 12][key_twin[track]]->Play(0, 0, DSBPLAY_LOOPING);
}
- else
+ else // 違う音を鳴らすなら (If you make a different sound)
{
- lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Play(false);
+ lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Play(0, 0, 0); // 今なっているのを歩かせ停止 (Stop playback now)
key_twin[track]++;
- if (key_twin[track] == 2)
+ if (key_twin[track] > 1)
key_twin[track] = 0;
- ChangeOrganFrequency(key % 12, track, freq);
- lpORGANBUFFER[track][key / 12][key_twin[track]]->Play(true);
+ 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;
}
}
}
-// Release tracks
+// オルガーニャオブジェクトを開放 (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)
@@ -261,236 +359,311 @@
}
}
-// Handling WAVE100
+// 波形データをロード (Load waveform data)
signed char wave_data[100][0x100];
-BOOL InitWaveData100()
+BOOL InitWaveData100(void)
{
- HRSRC hrscr = FindResourceA(NULL, "WAVE100", "WAVE");
+ HRSRC hrscr;
+ DWORD *lpdword; // リソースのアドレス (Resource address)
- if (hrscr == NULL)
+ if (lpDS == NULL)
return FALSE;
- const unsigned char *data = (unsigned char*)LockResource(LoadResource(NULL, hrscr));
+ // リソースの検索 (Search for resources)
+ hrscr = FindResourceA(NULL, "WAVE100", "WAVE");
- memcpy(wave_data, data, 100 * 0x100);
+ if (hrscr == NULL)
+ return FALSE;
+ // リソースのアドレスを取得 (Get resource address)
+ lpdword = (DWORD*)LockResource(LoadResource(NULL, hrscr));
+ memcpy(wave_data, lpdword, 100 * 0x100);
+
return TRUE;
}
-// Create org wave
+// 波形を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)
- {
- printf("WARNING: track %d has out-of-range wave_no %d\n", track, wave_no);
return FALSE;
- }
ReleaseOrganyaObject(track);
MakeSoundObject8(wave_data[wave_no], track, pipi);
+
return TRUE;
}
-// Dram
+/////////////////////////////////////////////
+//■オルガーニャドラムス■■■■■■■■/////// (Organya drums)
+/////////////////////
+
void ChangeDramFrequency(unsigned char key, signed char track)
{
- lpDRAMBUFFER[track]->SetFrequency(key * 800 + 100);
+ if (lpDS == NULL)
+ return;
+
+ lpSECONDARYBUFFER[150 + track]->SetFrequency(key * 800 + 100);
}
void ChangeDramPan(unsigned char pan, signed char track)
{
- lpDRAMBUFFER[track]->SetPan((pan_tbl[pan] - 0x100) * 10);
+ if (lpDS == NULL)
+ return;
+
+ lpSECONDARYBUFFER[150 + track]->SetPan((pan_tbl[pan] - 0x100) * 10);
}
void ChangeDramVolume(long volume, signed char track)
{
- lpDRAMBUFFER[track]->SetVolume((volume - 0xFF) * 8);
+ if (lpDS == NULL)
+ return;
+
+ lpSECONDARYBUFFER[150 + track]->SetVolume((volume - 0xFF) * 8);
}
+// サウンドの再生 (Play sound)
void PlayDramObject(unsigned char key, int mode, signed char track)
{
- switch (mode)
+ if (lpDS == NULL)
+ return;
+
+ if (lpSECONDARYBUFFER[150 + track] != NULL)
{
- case 0:
- lpDRAMBUFFER[track]->Stop();
- lpDRAMBUFFER[track]->SetCurrentPosition(0);
- break;
+ switch (mode)
+ {
+ case 0: // 停止 (Stop)
+ lpSECONDARYBUFFER[150 + track]->Stop();
+ lpSECONDARYBUFFER[150 + track]->SetCurrentPosition(0);
+ break;
- case 1:
- lpDRAMBUFFER[track]->Stop();
- lpDRAMBUFFER[track]->SetCurrentPosition(0);
- ChangeDramFrequency(key, track);
- lpDRAMBUFFER[track]->Play(false);
- break;
+ case 1: // 再生 (Playback)
+ lpSECONDARYBUFFER[150 + track]->Stop();
+ lpSECONDARYBUFFER[150 + track]->SetCurrentPosition(0);
+ ChangeDramFrequency(key, track); // 周波数を設定して ()
+ lpSECONDARYBUFFER[150 + track]->Play(0, 0, 0);
+ break;
- case 2:
- break;
+ case 2: // 歩かせ停止 (Stop playback)
+ break;
- case -1:
- break;
+ case -1:
+ break;
+ }
}
}
-// Play data
-long play_p;
-NOTELIST *play_np[MAXTRACK];
-long now_leng[MAXMELODY] = {0};
+OrgData::OrgData()
+{
+ int i;
-void OrganyaPlayData()
+ for (i = 0; i < MAXTRACK; i++)
+ {
+ info.tdata[i].note_list = NULL;
+ info.tdata[i].note_p = NULL;
+ }
+}
+
+void OrgData::InitOrgData(void)
{
- // Handle fading out
- if (bFadeout && gOrgVolume)
- gOrgVolume -= 2;
- if (gOrgVolume < 0)
- gOrgVolume = 0;
+ 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;
- // Play melody
- for (int i = 0; i < MAXMELODY; i++)
+ int i;
+ for (i = 0; i < MAXTRACK; i++)
{
- if (play_np[i] != NULL && play_p == play_np[i]->x)
- {
- if (play_np[i]->y != KEYDUMMY)
- {
- PlayOrganObject(play_np[i]->y, -1, i, info.tdata[i].freq);
- now_leng[i] = play_np[i]->length;
- }
+ info.tdata[i].freq = 1000;
+ info.tdata[i].wave_no = 0;
+ info.tdata[i].pipi = 0;
+ }
- if (play_np[i]->pan != PANDUMMY)
- ChangeOrganPan(play_np[i]->y, play_np[i]->pan, i);
- if (play_np[i]->volume != VOLDUMMY)
- gTrackVol[i] = play_np[i]->volume;
+ NoteAlloc(info.alloc_note);
+ SetMusicInfo(&info, SETALL);
- play_np[i] = play_np[i]->to;
- }
+ def_pan = DEFPAN;
+ def_volume = DEFVOLUME;
+}
- if (now_leng[i] == 0)
- PlayOrganObject(0, 2, i, info.tdata[i].freq);
+// 曲情報を設定。flagはアイテムを指定 (Set song information. flag specifies an item)
+BOOL OrgData::SetMusicInfo(MUSICINFO *mi, unsigned long flag)
+{
+#ifndef FIX_BUGS // Leftover debug junk
+ char str[32];
+#endif
+ int i;
- if (now_leng[i] > 0)
- now_leng[i]--;
+ if (flag & SETGRID) // グリッドを有効に (Enable grid)
+ {
+ info.dot = mi->dot;
+ info.line = mi->line;
+ }
- if (play_np[i])
- ChangeOrganVolume(play_np[i]->y, gOrgVolume * gTrackVol[i] / 0x7F, i);
+ if (flag & SETWAIT)
+ {
+ info.wait = mi->wait;
+#ifndef FIX_BUGS
+ itoa(mi->wait, str, 10);
+#endif
}
- for (int i = MAXMELODY; i < MAXTRACK; i++)
+ if (flag & SETREPEAT)
{
- if (play_np[i] != NULL && play_p == play_np[i]->x)
+ info.repeat_x = mi->repeat_x;
+ info.end_x = mi->end_x;
+ }
+
+ if (flag & SETFREQ)
+ {
+ for (i = 0; i < MAXMELODY; i++)
{
- if (play_np[i]->y != KEYDUMMY)
- PlayDramObject(play_np[i]->y, 1, i - MAXMELODY);
+ info.tdata[i].freq = mi->tdata[i].freq;
+ info.tdata[i].pipi = info.tdata[i].pipi;
+ }
+ }
- if (play_np[i]->pan != PANDUMMY)
- ChangeDramPan(play_np[i]->pan, i - MAXMELODY);
- if (play_np[i]->volume != VOLDUMMY)
- gTrackVol[i] = play_np[i]->volume;
+ if (flag & SETWAVE)
+ for (i = 0; i < MAXTRACK; i++)
+ info.tdata[i].wave_no = mi->tdata[i].wave_no;
- play_np[i] = play_np[i]->to;
- }
+ if (flag & SETPIPI)
+ for (i = 0; i < MAXTRACK; i++)
+ info.tdata[i].pipi = mi->tdata[i].pipi;
- if (play_np[i])
- ChangeDramVolume(gOrgVolume * gTrackVol[i] / 0x7F, i - MAXMELODY);
- }
+ return TRUE;
+}
- // Looping
- play_p++;
- if (play_p >= info.end_x)
+// 指定の数だけNoteDataの領域を確保(初期化) (Allocate the specified number of NoteData areas (initialization))
+BOOL OrgData::NoteAlloc(unsigned short alloc)
+{
+ int i,j;
+
+ for (j = 0; j < MAXTRACK; j++)
{
- play_p = info.repeat_x;
- SetPlayPointer(play_p);
+ 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;
}
-void SetPlayPointer(long x)
+// NoteDataを開放 (Release NoteData)
+void OrgData::ReleaseNote(void)
{
for (int i = 0; i < MAXTRACK; i++)
{
- play_np[i] = info.tdata[i].note_list;
- while (play_np[i] != NULL && play_np[i]->x < x)
- play_np[i] = play_np[i]->to;
+ if (info.tdata[i].note_p != NULL)
+ {
+ free(info.tdata[i].note_p);
+ info.tdata[i].note_p = NULL;
+ }
}
-
- play_p = x;
}
-#define READ_LE16(pointer) pointer[0] | (pointer[1] << 8); pointer += 2;
-#define READ_LE32(pointer) pointer[0] | (pointer[1] << 8) | (pointer[2] << 16) | (pointer[3] << 24); pointer += 4;
+static const char pass[7] = "Org-01";
+static const char pass2[7] = "Org-02"; // Pipi
-// Load organya file
-void LoadOrganya(const char *name)
+BOOL OrgData::InitMusicData(const char *path)
{
- // Unload previous things
- OrganyaReleaseNote();
- memset(&info, 0, sizeof(info));
- OrganyaNoteAlloc(0xFFFF);
+ ORGANYADATA org_data;
+ NOTELIST *np;
+ int i,j;
+ char pass_check[6];
+ char ver = 0;
- // Stop currently playing notes
- memset(play_np, 0, sizeof(play_np));
- memset(old_key, 0xFF, sizeof(old_key));
- memset(key_on, 0, sizeof(key_on));
- memset(key_twin, 0, sizeof(key_twin));
- memset(now_leng, 0, sizeof(now_leng));
-
- // Open file
- HRSRC hrscr = FindResourceA(NULL, name, "ORG");
-
+ HRSRC hrscr = FindResourceA(0, path, "ORG");
if (hrscr == NULL)
- return;
+ return FALSE;
- const unsigned char *p = (unsigned char*)LockResource(LoadResource(NULL, hrscr));
+ unsigned char *p = (unsigned char*)LockResource(LoadResource(0, hrscr));
- // Version Check
- unsigned char ver = 0;
- char pass_check[6];
-
- memcpy(pass_check, p, 6);
+ memcpy(&pass_check[0], p, 6);
p += 6;
- if (!memcmp(pass_check, "Org-01", 6))
+ if(memcmp(pass_check, pass, 6) == 0)
ver = 1;
-
- if (!memcmp(pass_check, "Org-02", 6))
+ if(memcmp(pass_check, pass2, 6) == 0)
ver = 2;
- // if (!memcmp(pass_check, "Org-03", 6))
- // ver = 2;
+ if(ver == 0)
+ return FALSE;
- if (!ver)
- {
- printf("Failed to open .org, invalid version %s", pass_check);
- return;
- }
+ // 曲情報の読み込み (Loading song information)
+ memcpy(&org_data, p, sizeof(ORGANYADATA));
+ p += sizeof(ORGANYADATA);
- // Set song information
- info.wait = READ_LE16(p);
- info.line = *p++;
- info.dot = *p++;
- info.repeat_x = READ_LE32(p);
- info.end_x = READ_LE32(p);
+ // 曲の情報を設定 (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 (int i = 0; i < 16; i++)
+ for (i = 0; i < MAXTRACK; i++)
{
- info.tdata[i].freq = READ_LE16(p);
- info.tdata[i].wave_no = *p++;
- const signed char pipi = *p++;
- info.tdata[i].pipi = ver == 1 ? 0 : pipi;
- info.tdata[i].note_num = READ_LE16(p);
- }
+ info.tdata[i].freq = org_data.tdata[i].freq;
- // Load notes
- NOTELIST *np;
+ if (ver == 1)
+ info.tdata[i].pipi = 0;
+ else
+ info.tdata[i].pipi = org_data.tdata[i].pipi;
- for (int j = 0; j < 16; j++)
+ info.tdata[i].wave_no = org_data.tdata[i].wave_no;
+ }
+
+ // 音符のロード (Loading notes)
+ for (j = 0; j < MAXTRACK; j++)
{
- // The first note from is NULL
- if (info.tdata[j].note_num == 0)
+ // 最初の音符は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 note list
+ // リストを作る (Make a list)
np = info.tdata[j].note_p;
info.tdata[j].note_list = info.tdata[j].note_p;
np->from = NULL;
@@ -497,7 +670,7 @@
np->to = (np + 1);
np++;
- for (int i = 1; i < info.tdata[j].note_num; i++)
+ for (i = 1; i < org_data.tdata[j].note_num; i++)
{
np->from = (np - 1);
np->to = (np + 1);
@@ -504,171 +677,394 @@
np++;
}
- // The last note to is NULL
+ // 最後の音符のtoはNULL (The last note to is NULL)
np--;
np->to = NULL;
- // Set note properties
- np = info.tdata[j].note_p; // X position
- for (int i = 0; i < info.tdata[j].note_num; i++)
+ // 内容を代入 (Assign content)
+ np = info.tdata[j].note_p; // X座標 (X coordinate)
+ for (i = 0; i < org_data.tdata[j].note_num; i++)
{
- np->x = READ_LE32(p);
+ memcpy(&np->x, p, sizeof(long));
+ p += sizeof(long);
np++;
}
- np = info.tdata[j].note_p; // Y position
- for (int i = 0; i < info.tdata[j].note_num; i++)
+ np = info.tdata[j].note_p; // Y座標 (Y coordinate)
+ for (i = 0; i < org_data.tdata[j].note_num; i++)
{
- np->y = *p++;
+ memcpy(&np->y, p, sizeof(unsigned char));
+ p += sizeof(unsigned char);
np++;
}
- np = info.tdata[j].note_p; // Length
- for (int i = 0; i < info.tdata[j].note_num; i++)
+ np = info.tdata[j].note_p; // 長さ (Length)
+ for (i = 0; i < org_data.tdata[j].note_num; i++)
{
- np->length = *p++;
+ memcpy(&np->length, p, sizeof(unsigned char));
+ p += sizeof(unsigned char);
np++;
}
- np = info.tdata[j].note_p; // Volume
- for (int i = 0; i < info.tdata[j].note_num; i++)
+ np = info.tdata[j].note_p; // ボリューム (Volume)
+ for (i = 0; i < org_data.tdata[j].note_num; i++)
{
- np->volume = *p++;
+ memcpy(&np->volume, p, sizeof(unsigned char));
+ p += sizeof(unsigned char);
np++;
}
- np = info.tdata[j].note_p; // Pan
- for (int i = 0; i < info.tdata[j].note_num; i++)
+ np = info.tdata[j].note_p; // パン (Pan)
+ for (i = 0; i < org_data.tdata[j].note_num; i++)
{
- np->pan = *p++;
+ memcpy(&np->pan, p, sizeof(unsigned char));
+ p += sizeof(unsigned char);
np++;
}
}
- // Create waves
- for (int j = 0; j < 8; j++)
- MakeOrganyaWave(j, info.tdata[j].wave_no, info.tdata[j].pipi);
+ // データを有効に (Enable data)
+ for (j = 0; j < MAXMELODY; j++)
+ MakeOrganyaWave(j,info.tdata[j].wave_no, info.tdata[j].pipi);
+#ifndef FIX_BUGS
+ // 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);
+ }
+#endif
- // Reset position
- SetPlayPointer(0);
+ SetPlayPointer(0); // 頭出し (Cue)
- // Set as loaded
- info.loaded = TRUE;
+ return TRUE;
}
-void SetOrganyaPosition(unsigned int x)
+// 曲情報を取得 (Get song information)
+void OrgData::GetMusicInfo(MUSICINFO *mi)
{
- SetPlayPointer(x);
- gOrgVolume = 100;
- bFadeout = FALSE;
+ 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;
+ }
}
-unsigned int GetOrganyaPosition()
+/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
+//プロトタイプ宣言 (prototype declaration)
+/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
+
+BOOL InitMMTimer();
+BOOL StartTimer(DWORD dwTimer);
+VOID CALLBACK TimerProc(UINT uTID,UINT uMsg,DWORD dwUser,DWORD dwParam1,DWORD dwParam2);
+BOOL QuitMMTimer();
+
+/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
+//グローバル変数 (Global variable)
+/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
+static UINT ExactTime = 13; // 最小精度 (Minimum accuracy)
+static UINT TimerID = NULL;
+static BOOL nameless_flag;
+
+/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
+// タイマー精度を設定する。 (Set timer accuracy.)
+// この関数はアプリケーション初期化時に一度呼び出す。 (This function is called once when the application is initialized.)
+/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
+BOOL InitMMTimer()
{
- return play_p;
+ 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;
}
-void PlayOrganyaMusic()
+/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
+// タイマーを起動する。 (Start the timer.)
+// dwTimer 設定するタイマー間隔 (dwTimer Timer interval to be set)
+/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
+BOOL StartTimer(DWORD dwTimer)
{
- // Start timer
- OrganyaStartTimer(info.wait);
+ MMRESULT ret = NULL;
+ ExactTime = dwTimer;
+
+ // タイマーを生成する (Generate timer)
+ TimerID = timeSetEvent
+ (
+ dwTimer, // タイマー時間 (Timer time)
+ 10, // 許容できるタイマー精度 (Acceptable timer accuracy)
+ (LPTIMECALLBACK)TimerProc, // コールバックプロシージャ (Callback procedure)
+ NULL, // ユーザーがコールバック関数の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;
+
+ nameless_flag = TRUE;
+
+ return TRUE;
}
-BOOL ChangeOrganyaVolume(signed int volume)
+/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
+// タイマーのコールバック関数 (Timer callback function)
+/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
+VOID CALLBACK TimerProc(UINT uTID,UINT uMsg,DWORD dwUser,DWORD dwParam1,DWORD dwParam2)
{
- if (volume >= 0 && volume <= 100)
- {
- gOrgVolume = volume;
- return TRUE;
- }
-
- return FALSE;
+ DWORD dwNowTime;
+ dwNowTime = timeGetTime();
+ //===================================================================================
+ // ここにユーザー定義のソースを書く。 (Write user-defined source here.)
+ // 基本的に関数を呼び出すだけで処理は他の関数でするべきだろう。 (Basically just call a function and the process should be another function.)
+ //===================================================================================
+ org_data.PlayData();
}
-void StopOrganyaMusic()
+/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
+// タイマーリソースを開放する。 (Release timer resources.)
+// アプリケーション終了時に一度呼び出す。 (Call once when the application ends.)
+/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
+BOOL QuitMMTimer()
{
- // Stop timer
- OrganyaEndTimer();
+ MMRESULT ret;
- // Stop notes
- for (int i = 0; i < MAXMELODY; i++)
- PlayOrganObject(0, 2, i, 0);
+ if (!nameless_flag)
+ return FALSE;
- memset(old_key, 255, sizeof(old_key));
- memset(key_on, 0, sizeof(key_on));
- memset(key_twin, 0, sizeof(key_twin));
-}
+ if(TimerID != TIMERR_NOERROR)
+ {
+ // タイマーを使用中なら終了させる (Terminate timer if in use)
+ ret = timeKillEvent(TimerID);
+ if (ret != TIMERR_NOERROR)
+ return FALSE;
+ }
-void SetOrganyaFadeout()
-{
- bFadeout = TRUE;
+ // タイマーリソースを開放する (Release timer resources)
+ ret = timeEndPeriod(ExactTime);
+ if (ret != TIMERR_NOERROR)
+ return FALSE;
+
+ nameless_flag = FALSE;
+
+ return TRUE;
}
-// Org timer
-SDL_Thread *OrganyaTimer = NULL;
-BOOL bEndTimer = FALSE;
+// Play data
+long play_p;
+NOTELIST *play_np[MAXTRACK];
+long now_leng[MAXMELODY];
-int OrganyaPlayTimer(void *ptr)
+void OrgData::PlayData()
{
- SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
+ int i;
- // Set time for next step to play
- Uint32 NextTick = SDL_GetTicks() + info.wait;
+ // Handle fading out
+ if (bFadeout && gOrgVolume)
+ gOrgVolume -= 2;
+ if (gOrgVolume < 0)
+ gOrgVolume = 0;
- while (bEndTimer == FALSE)
+ // メロディの再生 (Play melody)
+ for (i = 0; i < MAXMELODY; i++)
{
- if (info.loaded)
+ if (play_np[i] != NULL && play_p == play_np[i]->x)
{
- // Play music
- OrganyaPlayData();
+ if (!g_mute[i] && play_np[i]->y != KEYDUMMY) // 音が来た。 (The sound has come.)
+ {
+ PlayOrganObject(play_np[i]->y, -1, i, info.tdata[i].freq);
+ now_leng[i] = play_np[i]->length;
+ }
- // Wait until this step is over
- while (NextTick > SDL_GetTicks())
- SDL_Delay(1);
+ if (play_np[i]->pan != PANDUMMY)
+ ChangeOrganPan(play_np[i]->y, play_np[i]->pan, i);
+ if (play_np[i]->volume != VOLDUMMY)
+ gTrackVol[i] = play_np[i]->volume;
- // Get time for next step to play
- while (NextTick <= SDL_GetTicks())
- NextTick += info.wait;
+ play_np[i] = play_np[i]->to; // 次の音符を指す (Points to the next note)
}
- else
+
+ if (now_leng[i] == 0)
+ PlayOrganObject(0, 2, i, info.tdata[i].freq);
+
+ if (now_leng[i] > 0)
+ now_leng[i]--;
+
+ if (play_np[i])
+ ChangeOrganVolume(play_np[i]->y, gTrackVol[i] * gOrgVolume / 0x7F, i);
+ }
+
+ // ドラムの再生 (Drum playback)
+ for (i = MAXMELODY; i < MAXTRACK; i++)
+ {
+ if (play_np[i] != NULL && play_p == play_np[i]->x) // 音が来た。 (The sound has come.)
{
- // Wait until the org is loaded
- SDL_Delay(1);
+ if (play_np[i]->y != KEYDUMMY && !g_mute[i]) // ならす (Tame)
+ PlayDramObject(play_np[i]->y, 1, i - MAXMELODY);
+
+ if (play_np[i]->pan != PANDUMMY)
+ ChangeDramPan(play_np[i]->pan, i - MAXMELODY);
+ if (play_np[i]->volume != VOLDUMMY)
+ gTrackVol[i] = play_np[i]->volume;
+
+ play_np[i] = play_np[i]->to; // 次の音符を指す (Points to the next note)
}
+
+ if (play_np[i])
+ ChangeDramVolume(gTrackVol[i] * gOrgVolume / 0x7F, i - MAXMELODY);
}
- return 0;
+ // Looping
+ play_p++;
+ if (play_p >= info.end_x)
+ {
+ play_p = info.repeat_x;
+ SetPlayPointer(play_p);
+ }
}
-void OrganyaStartTimer(unsigned int wait)
+void OrgData::SetPlayPointer(long x)
{
- OrganyaEndTimer();
- bEndTimer = FALSE;
- OrganyaTimer = SDL_CreateThread(OrganyaPlayTimer, "OrganyaPlayTimer", (void*)NULL);
+ for (int i = 0; i < MAXTRACK; i++)
+ {
+ play_np[i] = info.tdata[i].note_list;
+ while (play_np[i] != NULL && play_np[i]->x < x)
+ play_np[i] = play_np[i]->to; // 見るべき音符を設定 (Set note to watch)
+ }
+
+ play_p = x;
}
-void OrganyaEndTimer()
+// Start and end organya
+BOOL StartOrganya(LPDIRECTSOUND _lpDS, const char *path_wave) // Both arguments are ignored for some reason
{
- bEndTimer = TRUE; // Tell thread to end
- SDL_WaitThread(OrganyaTimer, NULL); // Wait for thread to end
- OrganyaTimer = NULL;
+ if (lpDS == NULL)
+ return FALSE;
+
+ if (!InitWaveData100())
+ return FALSE;
+
+ org_data.InitOrgData();
+
+ return TRUE;
}
-// Start and end organya
-void StartOrganya()
+// Load organya file
+BOOL LoadOrganya(const char *name)
{
- // Initialize org stuff
- InitWaveData100();
+ if (lpDS == NULL)
+ return FALSE;
+
+ if (!org_data.InitMusicData(name))
+ return FALSE;
+
+ gOrgVolume = 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);
+ gOrgVolume = 100;
+ bFadeout = FALSE;
+}
+
+unsigned int GetOrganyaPosition(void)
+{
+ if (lpDS == NULL)
+ return 0;
+
+ return play_p;
+}
+
+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;
+
+ gOrgVolume = volume;
+ return TRUE;
+}
+
+void StopOrganyaMusic()
+{
+ 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()
+{
+ bFadeout = TRUE;
+}
+
void EndOrganya()
{
+ if (lpDS == NULL)
+ return;
+
// End timer
- OrganyaEndTimer();
+ QuitMMTimer();
// Release everything related to org
- OrganyaReleaseNote();
+ org_data.ReleaseNote();
for (int i = 0; i < MAXMELODY; i++)
+ {
+ PlayOrganObject(0, 0, i, 0);
ReleaseOrganyaObject(i);
+ }
}
--- a/src/Organya.h
+++ b/src/Organya.h
@@ -1,50 +1,13 @@
#pragma once
+#include <dsound.h>
+
#include "WindowsWrapper.h"
-//Below are Organya song data structures
-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;
-};
-
-//Track data * 8
-struct TRACKDATA
-{
- unsigned short freq; //Frequency (1000 is default)
- unsigned char wave_no; //Waveform No.
- signed char pipi;
- unsigned short note_num; //Number of notes
-
- NOTELIST *note_p;
- NOTELIST *note_list;
-};
-
-//Unique information held in songs
-struct MUSICINFO
-{
- unsigned short wait;
- BOOL loaded;
- BOOL playing;
- 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[16];
-};
-
BOOL MakeOrganyaWave(signed char track, signed char wave_no, signed char pipi);
void OrganyaPlayData();
void SetPlayPointer(long x);
-void LoadOrganya(const char *name);
+BOOL LoadOrganya(const char *name);
void SetOrganyaPosition(unsigned int x);
unsigned int GetOrganyaPosition();
void PlayOrganyaMusic();
@@ -51,7 +14,5 @@
BOOL ChangeOrganyaVolume(signed int volume);
void StopOrganyaMusic();
void SetOrganyaFadeout();
-void OrganyaStartTimer(unsigned int wait);
-void OrganyaEndTimer();
-void StartOrganya();
+BOOL StartOrganya(LPDIRECTSOUND lpDS, const char *wave_filename);
void EndOrganya();
--- a/src/Sound.cpp
+++ b/src/Sound.cpp
@@ -1,6 +1,15 @@
// Some of the original source code for this file can be found here:
// https://github.com/shbow/organya/blob/master/source/Sound.cpp
+/*
+TODO - Code style
+Pixel's code was *extremely* Windows-centric, to the point of using
+things like ZeroMemory and LPCSTR instead of standard things like
+memset and const char*. For now, the decompilation is accurate despite
+not using these since they're just macros that evaluate to the portable
+equivalents.
+*/
+
#include "Sound.h"
#include <math.h>
@@ -8,333 +17,361 @@
#include <stdlib.h>
#include <string.h>
-#include "SDL.h"
+#include <dsound.h>
#include "WindowsWrapper.h"
+#include "CommonDefines.h"
#include "Organya.h"
#include "PixTone.h"
+#include "Tags.h"
#define FREQUENCY 44100
-#ifdef RASPBERRY_PI
-#define STREAM_SIZE 0x400 // Larger buffer to prevent stutter
-#else
-#define STREAM_SIZE 0x100 // FREQUENCY/200 rounded to the nearest power of 2 (SDL2 *needs* a power-of-2 buffer size)
-#endif
+LPDIRECTSOUND lpDS; // DirectSoundオブジェクト (DirectSound object)
+LPDIRECTSOUNDBUFFER lpPRIMARYBUFFER; // 一時バッファ (Temporary buffer)
+LPDIRECTSOUNDBUFFER lpSECONDARYBUFFER[SE_MAX];
-#define clamp(x, y, z) (((x) > (z)) ? (z) : ((x) < (y)) ? (y) : (x))
-
-//Audio device
-SDL_AudioDeviceID audioDevice;
-
-//Keep track of all existing sound buffers
-SOUNDBUFFER *soundBuffers;
-
-//Sound buffer code
-SOUNDBUFFER::SOUNDBUFFER(size_t bufSize)
+// DirectSoundの開始 (Starting DirectSound)
+BOOL InitDirectSound(HWND hwnd)
{
- //Lock audio buffer
- SDL_LockAudioDevice(audioDevice);
+ int i;
+ DSBUFFERDESC1 dsbd;
- //Set parameters
- size = bufSize;
+ // DirectDrawの初期化 (DirectDraw initialization)
+ if (DirectSoundCreate(NULL, &lpDS, NULL) != DS_OK)
+ {
+ lpDS = NULL;
+ StartOrganya(lpDS, "Org\\Wave.dat");
+ return FALSE;
+ }
- playing = false;
- looping = false;
- looped = false;
+ lpDS->SetCooperativeLevel(hwnd, DSSCL_EXCLUSIVE);
- frequency = 0.0;
- volume = 1.0;
- volume_l = 1.0;
- volume_r = 1.0;
- samplePosition = 0.0;
+ // 一次バッファの初期化 (Initializing the primary buffer)
+ ZeroMemory(&dsbd, sizeof(DSBUFFERDESC1));
+ dsbd.dwSize = sizeof(DSBUFFERDESC1);
+ dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;
+ lpDS->CreateSoundBuffer((DSBUFFERDESC*)&dsbd, &lpPRIMARYBUFFER, NULL);
- //Create waveform buffer
- data = new unsigned char[bufSize];
- memset(data, 0x80, bufSize);
+ for (i = 0; i < SE_MAX; i++)
+ lpSECONDARYBUFFER[i] = NULL;
- //Add to buffer list
- this->next = soundBuffers;
- soundBuffers = this;
+ StartOrganya(lpDS, "Org\\Wave.dat");
- //Unlock audio buffer
- SDL_UnlockAudioDevice(audioDevice);
+ return TRUE;
}
-SOUNDBUFFER::~SOUNDBUFFER()
+// DirectSoundの終了 (Exit DirectSound)
+void EndDirectSound(void)
{
- //Lock audio buffer
- SDL_LockAudioDevice(audioDevice);
+ int i;
- //Free buffer
- if (data)
- delete[] data;
+ if (lpDS == NULL)
+ return;
- //Remove from buffer list
- for (SOUNDBUFFER **soundBuffer = &soundBuffers; *soundBuffer != NULL; soundBuffer = &(*soundBuffer)->next)
- {
- if (*soundBuffer == this)
- {
- *soundBuffer = this->next;
- break;
- }
- }
+ EndOrganya();
- //Unlock audio buffer
- SDL_UnlockAudioDevice(audioDevice);
-}
+ for (i = 0; i < SE_MAX; i++)
+ if (lpSECONDARYBUFFER[i] != NULL)
+ lpSECONDARYBUFFER[i]->Release();
-void SOUNDBUFFER::Release()
-{
- //TODO: find a better and more stable(?) way to handle this function
- delete this;
+ if (lpPRIMARYBUFFER != NULL)
+ lpPRIMARYBUFFER->Release();
+
+ if (lpDS != NULL)
+ lpDS->Release();
+
+ lpDS = NULL;
}
-void SOUNDBUFFER::Lock(unsigned char **outBuffer, size_t *outSize)
+// サウンドの設定 (Sound settings)
+BOOL InitSoundObject(LPCSTR resname, int no)
{
- SDL_LockAudioDevice(audioDevice);
+ HRSRC hrscr;
+ DSBUFFERDESC1 dsbd;
+ DWORD *lpdword; // リソースのアドレス (Resource address)
- if (outBuffer != NULL)
- *outBuffer = data;
+ if (lpDS == NULL)
+ return TRUE;
- if (outSize != NULL)
- *outSize = size;
-}
+ // リソースの検索 (Search for resources)
+ if ((hrscr = FindResourceA(NULL, resname, "WAVE")) == NULL)
+ return FALSE;
-void SOUNDBUFFER::Unlock()
-{
- SDL_UnlockAudioDevice(audioDevice);
-}
+ // リソースのアドレスを取得 (Get resource address)
+ lpdword = (DWORD*)LockResource(LoadResource(NULL, hrscr));
-void SOUNDBUFFER::SetCurrentPosition(unsigned long dwNewPosition)
-{
- SDL_LockAudioDevice(audioDevice);
- samplePosition = dwNewPosition;
- SDL_UnlockAudioDevice(audioDevice);
-}
+ // 二次バッファの生成 (Create secondary buffer)
+ ZeroMemory(&dsbd, sizeof(DSBUFFERDESC1));
+ dsbd.dwSize = sizeof(DSBUFFERDESC1);
+ dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
+ dsbd.dwBufferBytes = *(DWORD*)((BYTE*)lpdword+0x36); // WAVEデータのサイズ (WAVE data size)
+ dsbd.lpwfxFormat = (LPWAVEFORMATEX)(lpdword+5);
-void SOUNDBUFFER::SetFrequency(unsigned long dwFrequency)
-{
- SDL_LockAudioDevice(audioDevice);
- frequency = (double)dwFrequency;
- SDL_UnlockAudioDevice(audioDevice);
-}
+ if (lpDS->CreateSoundBuffer((DSBUFFERDESC*)&dsbd, &lpSECONDARYBUFFER[no], NULL) != DS_OK)
+ return FALSE;
-float MillibelToVolume(long lVolume)
-{
- //Volume is in hundredths of decibels, from 0 to -10000
- lVolume = clamp(lVolume, (long)-10000, (long)0);
- return (float)pow(10.0, lVolume / 2000.0);
-}
+ LPVOID lpbuf1, lpbuf2;
+ DWORD dwbuf1, dwbuf2;
-void SOUNDBUFFER::SetVolume(long lVolume)
-{
- SDL_LockAudioDevice(audioDevice);
- volume = MillibelToVolume(lVolume);
- SDL_UnlockAudioDevice(audioDevice);
-}
+ // 二次バッファのロック (Secondary buffer lock)
+ lpSECONDARYBUFFER[no]->Lock(0, *(DWORD*)((BYTE*)lpdword+0x36), &lpbuf1, &dwbuf1, &lpbuf2, &dwbuf2, 0);
-void SOUNDBUFFER::SetPan(long lPan)
-{
- SDL_LockAudioDevice(audioDevice);
- volume_l = MillibelToVolume(-lPan);
- volume_r = MillibelToVolume(lPan);
- SDL_UnlockAudioDevice(audioDevice);
-}
+ // 音源データの設定 (Sound source data settings)
+ CopyMemory(lpbuf1, (BYTE*)lpdword+0x3A, dwbuf1);
-void SOUNDBUFFER::Play(bool bLooping)
-{
- SDL_LockAudioDevice(audioDevice);
- playing = true;
- looping = bLooping;
- SDL_UnlockAudioDevice(audioDevice);
-}
+ if (dwbuf2 != 0)
+ CopyMemory(lpbuf2, (BYTE*)lpdword+0x3A+dwbuf1, dwbuf2);
-void SOUNDBUFFER::Stop()
-{
- SDL_LockAudioDevice(audioDevice);
- playing = false;
- SDL_UnlockAudioDevice(audioDevice);
+ // 二次バッファのロック解除 (Unlock secondary buffer)
+ lpSECONDARYBUFFER[no]->Unlock(lpbuf1, dwbuf1, lpbuf2, dwbuf2);
+
+ return TRUE;
}
-void SOUNDBUFFER::Mix(float *buffer, size_t frames)
+BOOL LoadSoundObject(LPCSTR file_name, int no)
{
- if (!playing) //This sound buffer isn't playing
- return;
+ char path[PATH_LENGTH];
+ DWORD i;
+ DWORD file_size = 0;
+ char check_box[58];
+ FILE *fp;
+ HANDLE hFile;
- for (size_t i = 0; i < frames; ++i)
- {
- const double freqPosition = frequency / FREQUENCY; //This is added to position at the end
+ sprintf(path, "%s\\%s", gModulePath, file_name);
- //Get the in-between sample this is (linear interpolation)
- const float sample1 = ((looped || ((size_t)samplePosition) >= 1) ? data[(size_t)samplePosition] : 128.0f);
- const float sample2 = ((looping || (((size_t)samplePosition) + 1) < size) ? data[(((size_t)samplePosition) + 1) % size] : 128.0f);
+ if (lpDS == NULL)
+ return TRUE;
- //Interpolate sample
- const float subPos = (float)fmod(samplePosition, 1.0);
- const float sampleA = sample1 + (sample2 - sample1) * subPos;
+ hFile = CreateFileA(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return FALSE;
- //Convert sample to float32
- const float sampleConvert = (sampleA - 128.0f) / 128.0f;
+ file_size = GetFileSize(hFile, NULL);
+ CloseHandle(hFile);
- //Mix
- *buffer++ += (float)(sampleConvert * volume * volume_l);
- *buffer++ += (float)(sampleConvert * volume * volume_r);
+ if ((fp = fopen(path, "rb")) == NULL)
+ return FALSE;
- //Increment position
- samplePosition += freqPosition;
+ for (i = 0; i < 58; i++)
+ fread(&check_box[i], sizeof(char), 1, fp);
- if (samplePosition >= size)
- {
- if (looping)
- {
- samplePosition = fmod(samplePosition, size);
- looped = true;
- }
- else
- {
- samplePosition = 0.0;
- playing = false;
- looped = false;
- break;
- }
- }
- }
-}
+ if (check_box[0] != 'R')
+ return FALSE;
+ if (check_box[1] != 'I')
+ return FALSE;
+ if (check_box[2] != 'F')
+ return FALSE;
+ if (check_box[3] != 'F')
+ return FALSE;
-//Sound mixer
-void AudioCallback(void *userdata, Uint8 *stream, int len)
-{
- (void)userdata;
+ DWORD *wp;
+ wp = (DWORD*)malloc(file_size); // ファイルのワークスペースを作る (Create a file workspace)
+ fseek(fp, 0, SEEK_SET);
- float *buffer = (float*)stream;
- const size_t frames = len / (sizeof(float) * 2);
+ for (i = 0; i < file_size; i++)
+ fread((BYTE*)wp+i, sizeof(BYTE), 1, fp);
- //Clear stream
- for (size_t i = 0; i < frames * 2; ++i)
- buffer[i] = 0.0f;
+ fclose(fp);
- //Mix sounds to primary buffer
- for (SOUNDBUFFER *sound = soundBuffers; sound != NULL; sound = sound->next)
- sound->Mix(buffer, frames);
-}
+ // セカンダリバッファの生成 (Create secondary buffer)
+ DSBUFFERDESC1 dsbd;
+ ZeroMemory(&dsbd, sizeof(DSBUFFERDESC1));
+ dsbd.dwSize = sizeof(DSBUFFERDESC1);
+ dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
+ dsbd.dwBufferBytes = *(DWORD*)((BYTE*)wp+0x36); // WAVEデータのサイズ (WAVE data size)
+ dsbd.lpwfxFormat = (LPWAVEFORMATEX)(wp+5);
-//Sound things
-SOUNDBUFFER* lpSECONDARYBUFFER[SE_MAX];
+ if (lpDS->CreateSoundBuffer((DSBUFFERDESC*)&dsbd, &lpSECONDARYBUFFER[no], NULL) != DS_OK)
+ {
+#ifdef FIX_BUGS
+ free(wp); // The updated Organya source code includes this fix
+#endif
+ return FALSE;
+ }
-BOOL InitDirectSound()
-{
- //Init sound
- SDL_InitSubSystem(SDL_INIT_AUDIO);
+ LPVOID lpbuf1, lpbuf2;
+ DWORD dwbuf1, dwbuf2;
- //Open audio device
- SDL_AudioSpec want, have;
+ HRESULT hr;
+ hr = lpSECONDARYBUFFER[no]->Lock(0, *(DWORD*)((BYTE*)wp+0x36), &lpbuf1, &dwbuf1, &lpbuf2, &dwbuf2, 0);
- //Set specifications we want
- SDL_memset(&want, 0, sizeof(want));
- want.freq = FREQUENCY;
- want.format = AUDIO_F32;
- want.channels = 2;
- want.samples = STREAM_SIZE;
- want.callback = AudioCallback;
-
- audioDevice = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
-
- if (audioDevice == 0)
+ if (hr != DS_OK)
{
- printf("Failed to open audio device\nSDL Error: %s\n", SDL_GetError());
+#ifdef FIX_BUGS
+ free(wp); // The updated Organya source code includes this fix
+#endif
return FALSE;
}
- //Unpause audio device
- SDL_PauseAudioDevice(audioDevice, 0);
+ CopyMemory(lpbuf1, (BYTE*)wp+0x3A, dwbuf1); // +3aはデータの頭 (+ 3a is the head of the data)
- for (unsigned int i = 0; i < SE_MAX; ++i)
- lpSECONDARYBUFFER[i] = NULL;
+ if (dwbuf2 != 0)
+ CopyMemory(lpbuf2, (BYTE*)wp+0x3A+dwbuf1, dwbuf2);
- //Start organya
- StartOrganya();
+ lpSECONDARYBUFFER[no]->Unlock(lpbuf1, dwbuf1, lpbuf2, dwbuf2);
+
+ free(wp);
+
return TRUE;
}
-void EndDirectSound()
-{
- EndOrganya();
-
- for (unsigned int i = 0; i < SE_MAX; ++i)
- if (lpSECONDARYBUFFER[i])
- lpSECONDARYBUFFER[i]->Release();
-
- SDL_QuitSubSystem(SDL_INIT_AUDIO);
-
- SDL_CloseAudioDevice(audioDevice);
-
-}
-
-//Sound effects playing
void PlaySoundObject(int no, int mode)
{
- if (lpSECONDARYBUFFER[no])
+ if (lpDS == NULL)
+ return;
+
+ if (lpSECONDARYBUFFER[no] != NULL)
{
switch (mode)
{
- case 0:
+ case 0: // 停止 (Stop)
lpSECONDARYBUFFER[no]->Stop();
break;
- case 1:
+ case 1: // 再生 (Playback)
lpSECONDARYBUFFER[no]->Stop();
lpSECONDARYBUFFER[no]->SetCurrentPosition(0);
- lpSECONDARYBUFFER[no]->Play(false);
+ lpSECONDARYBUFFER[no]->Play(0, 0, 0);
break;
- case -1:
- lpSECONDARYBUFFER[no]->Play(true);
+ case -1:// ループ再生 (Loop playback)
+ lpSECONDARYBUFFER[no]->Play(0, 0, DSBPLAY_LOOPING);
break;
}
}
}
-void ChangeSoundFrequency(int no, unsigned long rate)
+void ChangeSoundFrequency(int no, DWORD rate) // 100がMIN9999がMAXで2195?がノーマル (100 is MIN, 9999 is MAX, and 2195 is normal)
{
+ if (lpDS == NULL)
+ return;
+
lpSECONDARYBUFFER[no]->SetFrequency((rate * 10) + 100);
}
-void ChangeSoundVolume(int no, long volume)
+void ChangeSoundVolume(int no, long volume) // 300がMAXで300がノーマル (300 is MAX and 300 is normal)
{
+ if (lpDS == NULL)
+ return;
+
lpSECONDARYBUFFER[no]->SetVolume((volume - 300) * 8);
}
-void ChangeSoundPan(int no, long pan)
+void ChangeSoundPan(int no, long pan) // 512がMAXで256がノーマル (512 is MAX and 256 is normal)
{
+ if (lpDS == NULL)
+ return;
+
lpSECONDARYBUFFER[no]->SetPan((pan - 256) * 10);
}
int MakePixToneObject(const PIXTONEPARAMETER *ptp, int ptp_num, int no)
{
- int sample_count = 0;
- for (int i = 0; i < ptp_num; ++i)
+ typedef struct WavHeader
{
- if (ptp[i].size > sample_count)
- sample_count = ptp[i].size;
+ char riff_header[4];
+ unsigned long wav_size;
+ char wav_header[4];
+ char fmt_header[4];
+ unsigned long fmt_chunk_size;
+ unsigned short audio_format;
+ unsigned short num_channels;
+ unsigned long sample_rate;
+ unsigned long byte_rate;
+ unsigned short sample_alignment;
+ unsigned short bit_depth;
+ char data_header[4];
+ unsigned long data_bytes;
+ } WavHeader;
+
+ int i;
+ int j;
+ DSBUFFERDESC1 dsbd;
+ WavHeader wav_header;
+ const PIXTONEPARAMETER *ptp_pointer;
+ int sample_count;
+ unsigned char *pcm_buffer;
+ unsigned char *mixed_pcm_buffer;
+
+ if (lpDS == NULL)
+ return 0;
+
+ const char *riff = "RIFF";
+ const char *fmt = "fmt ";
+ const char *wave = "WAVE";
+ const char *data = "data";
+
+ wav_header.bit_depth = 8;
+ wav_header.sample_rate = 22050;
+ wav_header.num_channels = 1;
+ wav_header.audio_format = WAVE_FORMAT_PCM;
+ wav_header.fmt_chunk_size = 16;
+ memcpy(wav_header.riff_header, riff, 4);
+ memcpy(wav_header.fmt_header, fmt, 4);
+ memcpy(wav_header.wav_header, wave, 4);
+ memcpy(wav_header.data_header, data, 4);
+ wav_header.sample_alignment = (wav_header.bit_depth / 8) * wav_header.num_channels;
+ wav_header.byte_rate = (wav_header.bit_depth / 8) * wav_header.num_channels * wav_header.sample_rate;
+ wav_header.data_bytes = wav_header.sample_alignment * ptp->size;
+ wav_header.wav_size = wav_header.data_bytes + 36;
+
+ ptp_pointer = ptp;
+ sample_count = 0;
+
+ for (i = 0; i < ptp_num; i++)
+ {
+ if (ptp_pointer->size > sample_count)
+ sample_count = ptp_pointer->size;
+
+ ++ptp_pointer;
}
- unsigned char *pcm_buffer = (unsigned char*)malloc(sample_count);
- unsigned char *mixed_pcm_buffer = (unsigned char*)malloc(sample_count);
+ ZeroMemory(&dsbd, sizeof(DSBUFFERDESC1));
+ dsbd.dwSize = sizeof(DSBUFFERDESC1);
+ dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
+ dsbd.dwBufferBytes = sample_count;
+ dsbd.lpwfxFormat = (WAVEFORMATEX*)&wav_header.audio_format;
+
+ if (lpDS->CreateSoundBuffer((DSBUFFERDESC*)&dsbd, &lpSECONDARYBUFFER[no], 0) != DS_OK)
+ return -1;
+
+ pcm_buffer = mixed_pcm_buffer = NULL;
+
+ pcm_buffer = (unsigned char*)malloc(sample_count);
+ mixed_pcm_buffer = (unsigned char*)malloc(sample_count);
+
+ if (pcm_buffer == NULL || mixed_pcm_buffer == NULL)
+ {
+ if (pcm_buffer != NULL)
+ free(pcm_buffer);
+
+ if (mixed_pcm_buffer != NULL)
+ free(mixed_pcm_buffer);
+
+ return -1;
+ }
+
memset(pcm_buffer, 0x80, sample_count);
memset(mixed_pcm_buffer, 0x80, sample_count);
- for (int i = 0; i < ptp_num; ++i)
+ ptp_pointer = ptp;
+
+ for (i = 0; i < ptp_num; i++)
{
- if (!MakePixelWaveData(&ptp[i], pcm_buffer))
+ if (!MakePixelWaveData(ptp_pointer, pcm_buffer))
{
- free(pcm_buffer);
- free(mixed_pcm_buffer);
+ if (pcm_buffer)
+ free(pcm_buffer);
+
+ if (mixed_pcm_buffer)
+ free(mixed_pcm_buffer);
+
return -1;
}
- for (int j = 0; j < ptp[i].size; ++j)
+ for (j = 0; j < ptp_pointer->size; j++)
{
if (pcm_buffer[j] + mixed_pcm_buffer[j] - 0x100 < -0x7F)
mixed_pcm_buffer[j] = 0;
@@ -341,20 +378,33 @@
else if (pcm_buffer[j] + mixed_pcm_buffer[j] - 0x100 > 0x7F)
mixed_pcm_buffer[j] = 0xFF;
else
- mixed_pcm_buffer[j] += pcm_buffer[j] + -0x80;
+ mixed_pcm_buffer[j] = mixed_pcm_buffer[j] + pcm_buffer[j] - 0x80;
}
+
+ ++ptp_pointer;
}
- lpSECONDARYBUFFER[no] = new SOUNDBUFFER(sample_count);
+ // Maybe this used to be something to prevent audio popping?
+ mixed_pcm_buffer[0] = mixed_pcm_buffer[0];
+ mixed_pcm_buffer[sample_count - 1] = mixed_pcm_buffer[sample_count - 1];
- unsigned char *buf;
- lpSECONDARYBUFFER[no]->Lock(&buf, NULL);
- memcpy(buf, mixed_pcm_buffer, sample_count);
- lpSECONDARYBUFFER[no]->Unlock();
- lpSECONDARYBUFFER[no]->SetFrequency(22050);
+ LPVOID lpbuf1, lpbuf2;
+ DWORD dwbuf1, dwbuf2;
- free(pcm_buffer);
- free(mixed_pcm_buffer);
+ lpSECONDARYBUFFER[no]->Lock(0, sample_count, &lpbuf1, &dwbuf1, &lpbuf2, &dwbuf2, 0);
+
+ CopyMemory(lpbuf1, mixed_pcm_buffer, dwbuf1);
+
+ if (dwbuf2 != 0)
+ CopyMemory(lpbuf2, mixed_pcm_buffer + dwbuf1, dwbuf2);
+
+ lpSECONDARYBUFFER[no]->Unlock(lpbuf1, dwbuf1, lpbuf2, dwbuf2);
+
+ if (pcm_buffer != NULL)
+ free(pcm_buffer);
+
+ if (mixed_pcm_buffer != NULL)
+ free(mixed_pcm_buffer);
return sample_count;
}
--- a/src/Sound.h
+++ b/src/Sound.h
@@ -2,52 +2,19 @@
#include <stddef.h>
+#include <dsound.h>
+
#include "WindowsWrapper.h"
#include "PixTone.h"
-class SOUNDBUFFER
-{
- public:
- SOUNDBUFFER(size_t bufSize);
- ~SOUNDBUFFER();
-
- void Release();
-
- void Lock(unsigned char **buffer, size_t *size);
- void Unlock();
-
- void SetCurrentPosition(unsigned long dwNewPosition);
- void SetFrequency(unsigned long dwFrequency);
- void SetVolume(long lVolume);
- void SetPan(long lPan);
- void Play(bool bLooping);
- void Stop();
-
- void Mix(float *buffer, size_t frames);
-
- SOUNDBUFFER *next;
-
- private:
- unsigned char *data;
- size_t size;
-
- bool playing;
- bool looping;
- bool looped;
-
- double frequency;
- double volume;
- double volume_l;
- double volume_r;
- double samplePosition;
-};
-
#define SE_MAX 160 // According to the Organya source code release, this is the real name for this constant
-extern SOUNDBUFFER* lpSECONDARYBUFFER[SE_MAX];
-BOOL InitDirectSound();
-void EndDirectSound();
+extern LPDIRECTSOUND lpDS;
+extern LPDIRECTSOUNDBUFFER lpSECONDARYBUFFER[SE_MAX];
+
+BOOL InitDirectSound(HWND hwnd);
+void EndDirectSound(void);
void PlaySoundObject(int no, int mode);
void ChangeSoundFrequency(int no, unsigned long rate);
void ChangeSoundVolume(int no, long volume);