• R/O
  • SSH
  • HTTPS

dxruby: Commit


Commit MetaInfo

Revision530 (tree)
Time2016-05-05 21:48:10
Authormirichi

Log Message

Ayameを同梱するためソース管理

Change Summary

Incremental Difference

--- Ayame/VoiceElement.h (nonexistent)
+++ Ayame/VoiceElement.h (revision 530)
@@ -0,0 +1,248 @@
1+/**
2+ * @file VoiceElement.h
3+ * @brief 単一のサウンド管理クラス
4+ * @author Sazanta
5+ */
6+#ifndef __VOICEELEMENT_H__
7+#define __VOICEELEMENT_H__
8+#include <windows.h>
9+
10+#define NUM_OF_SUB_VOLUME 0 //!< サブボリュームの数
11+
12+const INT32 cnVoiceElm_VolumeMin = 0; //!< 最小ボリューム値
13+const INT32 cnVoiceElm_VolumeMax = 128; //!< 最大ボリューム値
14+const INT32 cnVoiceElm_VolumeRange = (cnVoiceElm_VolumeMax - cnVoiceElm_VolumeMin); //!< ボリューム範囲
15+const INT32 cnVoiceElm_PanpotCenter = 0; //!< パンセンター値
16+const INT32 cnVoiceElm_PanpotMaxR = 128; //!< 右パン最大値
17+const INT32 cnVoiceElm_PanpotMaxL = -128; //!< 左パン最大値
18+const INT32 cnVoiceElm_PanpotRange = (cnVoiceElm_PanpotMaxR - cnVoiceElm_PanpotMaxL); //!< パン範囲
19+const INT32 cnVoiceElm_PanpotHalfRange = (cnVoiceElm_PanpotRange / 2); //!< パン範囲(ハーフ)
20+
21+
22+//! CVoiceElementクラス
23+/**
24+ * このクラスは、サウンドのフェード・オートパンといった時間変位を行うためのクラスです。<br>
25+ * ポーズ時にフェードを行う際、ボリュームを保存するので、ポーズ解除時に元のボリュームに戻すことが出来ます。<br>
26+ * またマスターボリュームをサポートするための機構も備えています。<br>
27+ * 1つのクラスにつき、1つのボイスを管理することが出来ます。<br>
28+ * 単体でも使用することは出来ますが、通常はサウンドマネージャ等によって管理されます。<br>
29+ * このクラス自体は、インターフェイスを提供するだけですので、実際にはこのクラスから派生したクラスを利用します。<br>
30+ */
31+class CVoiceElement
32+{
33+ class CFadeValue
34+ {
35+ private:
36+ INT32 m_nNowValue; //!< 現在の値
37+ INT32 m_nNowTick; //!< 現在のタイム
38+ INT32 m_nTotalTick; //!< 総タイム
39+ INT32 m_nStartVal; //!< 開始値
40+ INT32 m_nDistVal; //!< 範囲値
41+
42+ public:
43+ CFadeValue(void) {
44+ m_nNowTick = 0;
45+ }
46+ ~CFadeValue(void) {}
47+
48+ bool IsFade(void) const {
49+ return (m_nNowTick > 0);
50+ }
51+ void ResetTime(void) {
52+ m_nNowTick = 0;
53+ }
54+ INT32 GetNowValue(void) const {
55+ return m_nNowValue;
56+ }
57+ void SetNowValue(INT32 nValue) {
58+ m_nNowValue = nValue;
59+ }
60+ void SetParam(INT32 nTick, INT32 nStart, INT32 nEnd) {
61+ m_nNowTick = nTick;
62+ m_nTotalTick = nTick;
63+ m_nStartVal = nEnd;
64+ m_nDistVal = nStart - nEnd;
65+ }
66+
67+ INT32 GetCalcValue(void) const {
68+ return ((m_nDistVal * m_nNowTick) / m_nTotalTick) + m_nStartVal;
69+ }
70+ bool Run(INT32 nTick, INT32& nValue) {
71+ if (m_nNowTick <= 0) return false;
72+ m_nNowTick -= nTick;
73+ if (m_nNowTick < 0) {
74+ m_nNowTick = 0;
75+ }
76+ nValue = GetCalcValue();
77+ return true;
78+ }
79+ };
80+
81+ protected:
82+ UINT32 m_dwNumber; //!< ボイスナンバー
83+ UINT32 m_dwUnique; //!< 識別ID
84+ bool m_bFinishRequest; //!< フェード後終了要求
85+ bool m_bPauseRequest; //!< フェード後ポーズ要求
86+ bool m_bPause; //!< ポーズ中フラグ
87+ bool m_bVolumeFade; //!< ボリュームフェード中フラグ
88+
89+ CFadeValue m_cVolume; //!< ボリューム
90+#if defined(NUM_OF_SUB_VOLUME) && (NUM_OF_SUB_VOLUME > 0)
91+ CFadeValue m_cSubVolume[NUM_OF_SUB_VOLUME]; //!< サブボリューム
92+#endif
93+ CFadeValue m_cPanpot; //!< パンポット
94+
95+ static INT32 m_snGlobalVol; //!< グローバルボリューム
96+
97+ protected:
98+ void AbortFade(void);
99+ void InternalFade(INT32 nVolume, INT32 nTick = 0, INT32 nStartVolume = -1);
100+ INT32 InternalGetVolume(void) const;
101+ INT32 CalculateSubVolume(void) const;
102+ void VolumeClamp(INT32& nVolume) const {
103+ nVolume = (nVolume < cnVoiceElm_VolumeMin)? cnVoiceElm_VolumeMin : ((nVolume > cnVoiceElm_VolumeMax)? cnVoiceElm_VolumeMax : nVolume);
104+ }
105+
106+ virtual void _Release(void) {}
107+ virtual void _SetPan(INT32 nPan) {}
108+ virtual void _SetVolume(INT32 nVolume) {}
109+ virtual void _SetSpeedRate(INT32 nRate) {}
110+ virtual void _Pause(void) {}
111+ virtual bool _Load(const char* pSoundData, UINT32 nDataSize, UINT32 nType) {
112+ return false;
113+ }
114+ virtual bool _Load(const TCHAR* pFileName, UINT32 nType, UINT32 nOffset, UINT32 nDataSize) {
115+ return false;
116+ }
117+ virtual bool _IsPlaying(void) const {
118+ return false;
119+ }
120+ virtual bool _IsFinished(void) const {
121+ return true;
122+ }
123+ virtual void _Play(UINT32 nLoop, UINT32 nLoopInSample = 0, UINT32 nStartPos = 0) {}
124+ virtual void _Stop(void) {}
125+ virtual void _Prefetch(void) {}
126+ virtual void _Predecode(void) {}
127+
128+ public:
129+ CVoiceElement(void);
130+ //! デストラクタ
131+ virtual ~CVoiceElement(void) {}
132+
133+ void Run(INT32 nTick);
134+
135+ //! ボイスナンバーの設定
136+ void SetNumber(UINT32 dwNumber) {
137+ m_dwNumber = dwNumber;
138+ }
139+ //! ボイスナンバーの取得
140+ UINT32 GetNumber(void) const {
141+ return m_dwNumber;
142+ }
143+
144+ //! 識別IDの設定
145+ void SetUnique(UINT32 dwUnique) {
146+ m_dwUnique = dwUnique;
147+ }
148+ //! 識別IDの取得
149+ UINT32 GetUnique(void) const {
150+ return m_dwUnique;
151+ }
152+
153+ //! データの作成
154+ /**
155+ * データの作成を行います。<br>
156+ */
157+ bool Load(const char* pSoundData, UINT32 nDataSize, UINT32 nFlag) {
158+ Release();
159+ return _Load(pSoundData, nDataSize, nFlag);
160+ }
161+ //! データの作成
162+ /**
163+ * データの作成を行います。<br>
164+ */
165+ bool Load(const TCHAR* pFileName, UINT32 nFlag, UINT32 nOffset, UINT32 nDataSize) {
166+ Release();
167+ return _Load(pFileName, nFlag, nOffset, nDataSize);
168+ }
169+ void Release(void);
170+
171+ //! 再生中かどうかチェック
172+ /**
173+ * 再生中かどうかを取得します。<br>
174+ *
175+ * @return 再生中ならtrue
176+ */
177+ bool IsPlaying(void) const
178+ {
179+ return _IsPlaying();
180+ }
181+ //! 停止完了チェック
182+ /**
183+ * 停止が完了したかどうかを取得します。<br>
184+ *
185+ * @return 停止完了ならtrue
186+ */
187+ bool IsFinished(void) const;
188+ //! フェード中かどうかチェック
189+ /**
190+ * フェード中かどうかを取得します。<br>
191+ *
192+ * @return フェード中ならtrue
193+ */
194+ bool IsFade(void) const {
195+ return m_cVolume.IsFade();
196+ }
197+ //! ポーズ中かどうかチェック
198+ /**
199+ * ポーズ中かどうかを取得します。<br>
200+ *
201+ * @return ポーズ中ならtrue
202+ */
203+ bool IsPause(void) const {
204+ return m_bPause;
205+ }
206+
207+ //! マスターボリュームの反映
208+ /**
209+ * マスターボリュームを即時反映させます。<br>
210+ */
211+ void ReflectMasterVolume(void) {
212+ if (IsFade() == false) {
213+ SetVolume(-1);
214+ }
215+ }
216+ INT32 GetVolume(void) const;
217+ void SetVolume(INT32 nVolume, INT32 nTick = 0, INT32 nStartVolume = -1);
218+ INT32 GetSubVolume(UINT32 nChannel) const;
219+ void SetSubVolume(UINT32 nChannel, INT32 nVolume, INT32 nTick = 0, INT32 nStartVolume = -1);
220+
221+ INT32 GetPan(void) const;
222+ void SetPan(INT32 nPan, INT32 nTick = 0, INT32 nStartPan = -(cnVoiceElm_PanpotHalfRange + 1));
223+
224+ INT32 GetSpeedRate(void) const {
225+ return 4096;
226+ }
227+ void SetSpeedRate(INT32 nRate) {
228+ _SetSpeedRate(nRate);
229+ }
230+
231+ void Play(UINT32 dwLoop = 0, INT32 nVolume = -1, INT32 nFadeInTick = 0, UINT32 nLoopInSample = 0);
232+ void Stop(INT32 nFadeOutTick = 0);
233+ void Pause(bool bPause, INT32 nFadeTick = 0);
234+ void Prefetch(void) {
235+ _Prefetch();
236+ }
237+ void Predecode(void) {
238+ _Predecode();
239+ }
240+
241+ static void SetGlobalVolume(INT32 nVolume) {
242+ m_snGlobalVol = (nVolume < cnVoiceElm_VolumeMin)? cnVoiceElm_VolumeMin : ((nVolume > cnVoiceElm_VolumeMax)? cnVoiceElm_VolumeMax : nVolume);
243+ }
244+};
245+
246+
247+#endif // __VOICEELEMENT_H__
248+/* Bottom of VoiceElement.h */
--- Ayame/VoiceElementMidi.h (nonexistent)
+++ Ayame/VoiceElementMidi.h (revision 530)
@@ -0,0 +1,86 @@
1+/**
2+ * @file VoiceElementMidi.h
3+ * @brief 単一のサウンド管理クラス
4+ * @author Sazanta
5+ */
6+#ifndef __VOICEELEMENTMIDI_H__
7+#define __VOICEELEMENTMIDI_H__
8+
9+// インクルード
10+#include "midi.h"
11+#include "VoiceElement.h"
12+
13+
14+//! CVoiceElementMidiクラス
15+/**
16+ * このクラスは、CMidiに対してのCVoiceElement操作を提供する派生クラスです。<br>
17+ * MIDIファイルの再生を行います。<br>
18+ */
19+class CVoiceElementMidi : public CVoiceElement
20+{
21+ protected:
22+ CMidi* m_pMidi;
23+
24+ void _Release(void) {
25+ if (m_pMidi != NULL) {
26+ m_pMidi->Release();
27+ m_pMidi = NULL;
28+ }
29+ }
30+ void _SetPan(INT32 nPan) {
31+ if (m_pMidi != NULL) {
32+ m_pMidi->SetMasterPanpot(64 + (INT32)(nPan / 2));
33+ }
34+ }
35+ void _SetVolume(INT32 nVolume) {
36+ if (m_pMidi != NULL) {
37+ m_pMidi->SetMasterVolume((UINT16)(nVolume * 2));
38+ }
39+ }
40+ void _Pause(void) {
41+ if (m_pMidi != NULL) {
42+ m_pMidi->Pause();
43+ }
44+ }
45+ bool _Load(const char* pSoundData, UINT32 nDataSize, UINT32 nFlag) {
46+ if (m_pMidi == NULL) {
47+ m_pMidi = new CMidi;
48+ }
49+ return m_pMidi->AttachMidiData((const unsigned char*)pSoundData, nDataSize);
50+ }
51+ bool _Load(const TCHAR* pFileName, UINT32 nFlag, UINT32 nOffset, UINT32 nDataSize) {
52+ if (m_pMidi == NULL) {
53+ m_pMidi = new CMidi;
54+ }
55+ return m_pMidi->AttachMidiFile(pFileName, nOffset, nDataSize);
56+ }
57+ bool _IsPlaying(void) const {
58+ if (m_pMidi == NULL) return false;
59+ return m_pMidi->IsPlaying();
60+ }
61+ bool _IsFinished(void) const {
62+ if (m_pMidi == NULL) return true;
63+ return (IsPause() == false && m_pMidi->IsPlaying() == false);
64+ }
65+ void _Play(UINT32 nLoop, UINT32 nLoopInSample = 0, UINT32 nStartPos = 0) {
66+ if (m_pMidi != NULL) {
67+ m_pMidi->Play(nLoop);
68+ }
69+ }
70+ void _Stop(void) {
71+ if (m_pMidi != NULL) {
72+ m_pMidi->Stop();
73+ }
74+ }
75+ public:
76+ CVoiceElementMidi(void) {
77+ m_pMidi = NULL;
78+ }
79+ virtual ~CVoiceElementMidi(void) {
80+ _Release();
81+ }
82+};
83+
84+
85+#endif // __VOICEELEMENTMIDI_H__
86+/* Bottom of VoiceElementMidi.h */
--- Ayame/extconf.rb (nonexistent)
+++ Ayame/extconf.rb (revision 530)
@@ -0,0 +1,16 @@
1+require "mkmf"
2+
3+SYSTEM_LIBRARIES = [
4+ "dsound",
5+ "ole32",
6+]
7+
8+SYSTEM_LIBRARIES.each do |lib|
9+ have_library(lib)
10+end
11+
12+#ヘッダファイル足りてませんが調べるの面倒で(^-^;
13+
14+#have_func("rb_enc_str_new")
15+
16+create_makefile("ayame")
--- Ayame/midi.h (nonexistent)
+++ Ayame/midi.h (revision 530)
@@ -0,0 +1,252 @@
1+/**
2+ * @brief MIDI再生クラス
3+ * @file midi.h
4+ * @author sazanta
5+ */
6+#include <windows.h>
7+#include <mmsystem.h>
8+
9+class CMidiEvent;
10+
11+enum eEventType
12+{
13+ EVT_LOAD,
14+ EVT_PLAY,
15+ EVT_STOP,
16+ EVT_PAUSE,
17+ EVT_RELEASE,
18+ EVT_MAX,
19+};
20+
21+struct EVENT_QUE_DATA_LOAD
22+{
23+ int nType; // 0-Memory 1-File 2-Url
24+ char *pData; // nTypeが0以外の場合はdeleteする
25+ unsigned long nSize;
26+ unsigned long nStart;
27+};
28+
29+struct EVENT_QUE_DATA_PLAY
30+{
31+ unsigned long nStartPos;
32+ unsigned long nLoopCount;
33+};
34+
35+struct EVENT_QUE
36+{
37+ eEventType EventType;
38+ bool bUse;
39+ union{
40+ EVENT_QUE_DATA_LOAD Data_Load;
41+ EVENT_QUE_DATA_PLAY Data_Play;
42+ };
43+};
44+
45+
46+//! MIDI再生クラス
47+class CMidi
48+{
49+ protected:
50+ CRITICAL_SECTION m_stCriticalSection; //!< クリティカルセクション
51+ HANDLE m_hThread; //!< スレッドハンドル
52+ unsigned long m_nThreadId; //!< スレッドID
53+ HANDLE m_hEvent; //!< イベント
54+ EVENT_QUE m_stQue[EVT_MAX]; //!< イベントキュー
55+
56+ CMidiEvent* m_pHeader; //!< データ先頭アドレス
57+ CMidiEvent* m_pNowPoint; //!< 現在のデータポインタ
58+ union {
59+ unsigned short m_nAttribute; //!< 属性
60+ struct {
61+ unsigned short m_nAttr_Pause : 1; //!< ポーズ中フラグ
62+ unsigned short m_nAttr_UpdateV : 1; //!< 音量更新フラグ
63+ unsigned short m_nAttr_UpdateP : 1; //!< パンポット更新フラグ
64+ unsigned short m_nIsPlayQue : 1; //!< 再生準備中フラグ
65+ unsigned short m_nAttr_pad :12;
66+ };
67+ };
68+ unsigned short m_nTimeBias; //!< 分解能バイアス
69+ unsigned long m_nTime; //!< 分解能
70+ unsigned long m_nTempo; //!< テンポ
71+ unsigned long m_nLoop; //!< ループ回数
72+ unsigned long m_nNowTime; //!< 現在の再生時間
73+ unsigned long m_nNowTimeRest; //!< 現在の再生余り時間
74+ unsigned long m_nNextTime; //!< 次のイベントを送出する時間
75+ unsigned long m_nPrevTime; //!< 前回処理を行った時間
76+ unsigned long m_nTimeRest; //!< 余り時間
77+ unsigned long m_nTotalTime; //!< トータル時間
78+ unsigned int m_nTimerID; //!< タイマーID
79+ HMIDIOUT m_hMidiOut;
80+
81+ unsigned char m_nPanpot[16]; //!< チャンネルパン
82+ unsigned short m_nVolume[16]; //!< チャンネルボリューム
83+ unsigned short m_nMasterVolume; //!< マスターボリューム
84+ unsigned short m_nMuteFlag; //!< ミュートフラグ
85+ unsigned char m_nMasterPanpot; //!< マスターパンポット
86+ volatile bool m_bEnd;
87+
88+ protected:
89+ virtual ~CMidi(void);
90+ bool AddQue(EVENT_QUE* pQue);
91+ void _Release(void);
92+ bool _AttachMidiFile(const char* pFileName, unsigned int nOfs, unsigned int nSize);
93+ bool _AttachMidiData(const unsigned char* pData, unsigned int nSize);
94+ bool _Play(unsigned int nLoop);
95+ bool _Stop(void);
96+ void _Pause(void);
97+ void ReleaseMain(CMidiEvent* pEvent);
98+ bool ReadTrack(unsigned char** ppData, CMidiEvent** lplpEvent, unsigned int& nSize);
99+ CMidiEvent* Marge(CMidiEvent** lplpEvent, unsigned short nTrack);
100+ unsigned char* ReadDelta(unsigned char* pData, unsigned long& nDelta, unsigned int& nSize);
101+ unsigned long CalcTotalTime(void) const;
102+ void ThreadMain();
103+ static void CALLBACK TimeCallbackProc(unsigned int nID, unsigned int nMsg, unsigned long nUser, unsigned long nReserve1, unsigned long nReserve2);
104+ static unsigned long CALLBACK ThreadProc(void *pParameter);
105+
106+ public:
107+ CMidi(void);
108+
109+ void Release(void);
110+ bool AttachMidiFile(const TCHAR* pFileName, unsigned int nOfs = 0, unsigned int nSize = 0);
111+ bool AttachMidiData(const unsigned char* pData, unsigned int nSize);
112+
113+ bool Play(unsigned long nLoop = 0xffffffff);
114+ bool Stop(void);
115+ bool Pause(void);
116+ //! 再生中かどうか
117+ /**
118+ * @return 再生中の場合はtrueを返す
119+ */
120+ bool IsPlaying(void) const {
121+ return (m_nIsPlayQue == true || m_pNowPoint != NULL);
122+ }
123+ //! 総時間の取得
124+ /**
125+ * @return 総時間(単位はms)
126+ */
127+ unsigned long GetTotalTime(void) const {
128+ return (m_pHeader != NULL)? m_nTotalTime : 0;
129+ }
130+ //! 再生時間の取得
131+ /**
132+ * @return 再生時間(単位はms)
133+ */
134+ unsigned long GetPlayingTime(void) const {
135+ return (m_pHeader != NULL)? m_nNowTime : 0;
136+ }
137+
138+ //! ループ回数の設定
139+ void SetLoopCounter(unsigned int nLoop) {
140+ if (m_pHeader != NULL) {
141+ m_nLoop = nLoop;
142+ }
143+ }
144+ //! ループ回数の取得
145+ unsigned long GetLoopCounter(void) const {
146+ return (m_pHeader != NULL)? m_nLoop : 0;
147+ }
148+
149+ unsigned short SetMuteFlag(unsigned short nFlag);
150+ unsigned short SetMuteFlag(unsigned int nChannel, bool bFlag);
151+ //! ミュートフラグの取得
152+ unsigned short GetMuteFlag(void) const {
153+ return m_nMuteFlag;
154+ }
155+
156+ //! テンポスピードの設定
157+ /**
158+ * @param nSpeed [in] テンポスピード(1000=1.0)
159+ */
160+ void SetTimeSpeed(unsigned long nSpeed) {
161+ m_nTimeBias = (unsigned short)((nSpeed == 0)? 1 : nSpeed);
162+ }
163+ //! テンポスピードの取得
164+ /**
165+ * @return テンポスピード(1000=1.0)
166+ */
167+ unsigned long GetTimeSpeed(void) const {
168+ return m_nTimeBias;
169+ }
170+
171+ //! テンポの取得
172+ unsigned long GetRealTempo(void) const {
173+ return m_nTempo;
174+ }
175+ //! テンポの取得
176+ unsigned long GetTempo(void) const {
177+ return (60 * 1000000) / m_nTempo;
178+ }
179+
180+ //! マスターボリュームの設定
181+ /**
182+ * @param nVol [in] マスターボリューム(0〜256)
183+ */
184+ void SetMasterVolume(unsigned short nVol) {
185+ m_nMasterVolume = ((nVol > 256)? 256 : nVol);
186+ m_nAttr_UpdateV = 1;
187+ }
188+ //! マスターボリュームの取得
189+ unsigned short GetMasterVolume(void) const {
190+ return m_nMasterVolume;
191+ }
192+
193+ //! チャンネルボリュームの設定
194+ /**
195+ * 各チャンネルのボリュームを指定します。
196+ * 各チャンネルのボリュームはMIDIデータによって上書きされる可能性があります。
197+ *
198+ * @param nChannel [in] チャンネル(0〜15)
199+ * @param nVol [in] チャンネルボリューム(0〜127)
200+ */
201+ void SetChannelVolume(unsigned long nChannel, unsigned short nVol) {
202+ if (nChannel >= 16) return;
203+ m_nVolume[nChannel] = (nVol > 127)? 127 : nVol;
204+ m_nAttr_UpdateV = 1;
205+ }
206+ //! チャンネルボリュームの取得
207+ /**
208+ * @return チャンネルボリューム
209+ */
210+ unsigned short GetChannelVolume(unsigned long nChannel) const {
211+ return (nChannel < 16)? m_nVolume[nChannel] : 100;
212+ }
213+
214+ //! マスターパンポットの設定
215+ /**
216+ * @param nPan [in] マスターパンポット(0〜127)
217+ */
218+ void SetMasterPanpot(unsigned char nPan) {
219+ m_nMasterPanpot = ((nPan > 127)? 127 : nPan);
220+ m_nAttr_UpdateP = 1;
221+ }
222+ //! マスターパンポットの取得
223+ unsigned char GetMasterPanpot(void) const {
224+ return m_nMasterPanpot;
225+ }
226+
227+ //! チャンネルパンポットの設定
228+ /**
229+ * 各チャンネルのパンポットを指定します。
230+ * 各チャンネルのパンポットはMIDIデータによって上書きされる可能性があります。
231+ *
232+ * @param nChannel [in] チャンネル(0〜15)
233+ * @param nPan [in] チャンネルパンポット(0〜127)
234+ */
235+ void SetChannelPanpot(unsigned long nChannel, unsigned char nPan) {
236+ if (nChannel >= 16) return;
237+ m_nPanpot[nChannel] = (nPan > 127)? 127 : nPan;
238+ m_nAttr_UpdateP = 1;
239+ }
240+ //! チャンネルパンポットの取得
241+ /**
242+ * @return チャンネルパンポット
243+ */
244+ unsigned char GetChannelPanpot(unsigned long nChannel) const {
245+ return (nChannel < 16)? m_nPanpot[nChannel] : 64;
246+ }
247+
248+ static bool CheckMidiHeader(const unsigned char* pData);
249+};
250+
251+
252+/* Bottom of midi.h */
--- Ayame/AyameManager.h (nonexistent)
+++ Ayame/AyameManager.h (revision 530)
@@ -0,0 +1,124 @@
1+/**
2+ * Ayameマネージャ
3+ */
4+
5+#ifndef ___AYAMEMANAGER_H___
6+#define ___AYAMEMANAGER_H___
7+
8+
9+//====================================================================
10+// INCLUDE
11+//====================================================================
12+#include <windows.h>
13+#include "Ayame.h"
14+
15+#ifdef _UNICODE
16+ #define DEFAULT_AYAME_PATH L"ayame.dll"
17+#else
18+ #define DEFAULT_AYAME_PATH "ayame.dll"
19+#endif
20+
21+//! Ayameマネージャ
22+class CAyameManager
23+{
24+protected:
25+ HINSTANCE m_hAyame;
26+ AYAME_INITIALIZE_PROC m_pAyameInitialize;
27+ AYAME_UNINITIALIZE_PROC m_pAyameUninitialize;
28+ AYAME_CREATE_FROM_FILE_PROC m_pAyameCreateFromFile;
29+ AYAME_CREATE_FROM_MEMORY_PROC m_pAyameCreateFromMemory;
30+ AYAME_CREATE_FROM_URL_PROC m_pAyameCreateFromUrl;
31+ AYAME_GETERROR_PROC m_pAyameGetError;
32+
33+public:
34+ //! コンストラクタ
35+ CAyameManager() {
36+ m_hAyame = NULL;
37+ m_pAyameInitialize = NULL;
38+ m_pAyameUninitialize = NULL;
39+ m_pAyameCreateFromFile = NULL;
40+ m_pAyameCreateFromMemory = NULL;
41+ m_pAyameCreateFromUrl = NULL;
42+ m_pAyameGetError = NULL;
43+ }
44+ //! デストラクタ
45+ ~CAyameManager() {
46+ Release();
47+ }
48+
49+ //! DLLの読み込み
50+ bool LoadDLL(HWND hWnd, TCHAR* pszPath = DEFAULT_AYAME_PATH, void **ppDirectSound = NULL) {
51+ if ( m_hAyame != NULL )
52+ {
53+ return false;
54+ }
55+ // DLLのロード
56+ m_hAyame = ::LoadLibrary( pszPath );
57+ if ( m_hAyame == NULL ) return false;
58+
59+ // 関数のロード
60+ m_pAyameInitialize = (AYAME_INITIALIZE_PROC)::GetProcAddress( m_hAyame, "Ayame_Initialize" );
61+ m_pAyameUninitialize = (AYAME_UNINITIALIZE_PROC)::GetProcAddress( m_hAyame, "Ayame_Uninitialize" );
62+ m_pAyameCreateFromFile = (AYAME_CREATE_FROM_FILE_PROC)::GetProcAddress( m_hAyame, "Ayame_CreateInstanceFromFile" );
63+ m_pAyameCreateFromMemory = (AYAME_CREATE_FROM_MEMORY_PROC)::GetProcAddress( m_hAyame, "Ayame_CreateInstanceFromMemory" );
64+ m_pAyameCreateFromUrl = (AYAME_CREATE_FROM_URL_PROC)::GetProcAddress( m_hAyame, "Ayame_CreateInstanceFromUrl" );
65+ m_pAyameGetError = (AYAME_GETERROR_PROC)::GetProcAddress( m_hAyame, "Ayame_GetLastError" );
66+
67+ if ( m_pAyameInitialize == NULL ||
68+ m_pAyameUninitialize == NULL ||
69+ m_pAyameCreateFromFile == NULL ||
70+ m_pAyameCreateFromMemory == NULL ||
71+ m_pAyameCreateFromUrl == NULL ||
72+ m_pAyameGetError == NULL )
73+ {
74+ ::FreeLibrary(m_hAyame);
75+ m_hAyame = NULL;
76+ return false;
77+ }
78+
79+ // ドライバーの初期化
80+ return m_pAyameInitialize( hWnd, ppDirectSound );
81+ }
82+
83+ //! DLLの開放
84+ void Release() {
85+ if ( m_hAyame != NULL )
86+ {
87+ m_pAyameUninitialize();
88+ ::FreeLibrary(m_hAyame);
89+ m_hAyame = NULL;
90+ }
91+ }
92+
93+ CAyame *CreateInstanceFromFile( const TCHAR *pFileName, unsigned long Start = 0, unsigned long Size = 0, unsigned long Flag = AYAME_LOADFLAG_GLOBAL )
94+ {
95+ if ( m_hAyame == NULL || pFileName == NULL )
96+ return NULL;
97+ return m_pAyameCreateFromFile( pFileName, Start, Size, Flag );
98+ }
99+
100+ CAyame *CreateInstanceFromMemory( const void *pData, unsigned long Size = 0, unsigned long Flag = AYAME_LOADFLAG_GLOBAL )
101+ {
102+ if ( m_hAyame == NULL || pData == NULL )
103+ return NULL;
104+ return m_pAyameCreateFromMemory( pData, Size, Flag );
105+ }
106+
107+ CAyame *CreateInstanceFromUrl( const TCHAR *pUrl, unsigned long Start = 0, unsigned long Size = 0, unsigned long Flag = AYAME_LOADFLAG_GLOBAL )
108+ {
109+ if ( m_hAyame == NULL || pUrl == NULL )
110+ return NULL;
111+ return m_pAyameCreateFromUrl( pUrl, Start, Size, Flag );
112+ }
113+
114+ bool GetLastError( TCHAR *pErrStr, unsigned long Size )
115+ {
116+ if ( m_hAyame == NULL )
117+ return false;
118+ return m_pAyameGetError( pErrStr, Size );
119+ }
120+};
121+
122+#endif // ___AYAMEMANAGER_H___
123+
124+
--- Ayame/VoiceElementAyame.cpp (nonexistent)
+++ Ayame/VoiceElementAyame.cpp (revision 530)
@@ -0,0 +1,14 @@
1+/**
2+ * @file VoiceElementAyame.cpp
3+ * @brief 単一のサウンド管理クラス
4+ * @author Sazanta
5+ */
6+
7+// インクルード
8+#include "VoiceElementAyame.h"
9+
10+
11+CAyameManager CVoiceElementAyame::m_sAyameMgr;
12+
13+
14+/* Bottom of VoiceElementAyame.cpp */
--- Ayame/ayame_ruby.cpp (nonexistent)
+++ Ayame/ayame_ruby.cpp (revision 530)
@@ -0,0 +1,461 @@
1+/*
2+###################################
3+#
4+# Ayame/Ruby 0.0.2
5+#
6+###################################
7+*/
8+
9+#include "ruby.h"
10+#include "VoiceElement.h"
11+#include "VoiceElementAyame.h"
12+#include "VoiceElementMidi.h"
13+
14+static VALUE cAyame;
15+static VALUE eAyameError; /* 例外 */
16+
17+struct AyameData {
18+ CVoiceElement* pVoiceElement;
19+ __int64 start_tick;
20+};
21+
22+static int g_isPerformanceCounter = 0; /* パフォーマンスカウンタがあったら1 */
23+static __int64 g_OneSecondCount = 0; /* 一秒間にカウンタが数える数 */
24+
25+static void InitSync( void );
26+static __int64 GetSystemCounter( void );
27+
28+#define AYAME_GET_STRUCT( v ) ((struct AyameData *)DATA_PTR( v ))
29+
30+/* 内部参照用リスト */
31+static struct AyameList {
32+ void **pointer;
33+ int allocate_size;
34+ int count;
35+} g_AyameList;
36+
37+static bool g_AyameShutdownFlag = false;
38+
39+
40+static void AddAyameList( struct AyameData *ad )
41+{
42+ if( g_AyameList.allocate_size <= g_AyameList.count )
43+ {
44+ g_AyameList.allocate_size = g_AyameList.allocate_size * 3 / 2; /* 1.5倍にする */
45+ g_AyameList.pointer = (void**)realloc( g_AyameList.pointer, sizeof( void* ) * g_AyameList.allocate_size );
46+ }
47+
48+ g_AyameList.pointer[g_AyameList.count] = ad;
49+ g_AyameList.count++;
50+}
51+
52+static void DeleteAyameList( struct AyameData *ad )
53+{
54+ int i;
55+
56+ for( i = 0; i < g_AyameList.count; i++ )
57+ {
58+ if( g_AyameList.pointer[i] == ad )
59+ {
60+ break;
61+ }
62+ }
63+ if( i == g_AyameList.count )
64+ {
65+ rb_raise( eAyameError, "内部エラー - DeleteAyameList" );
66+ }
67+
68+ i++;
69+ for( ; i < g_AyameList.count; i++ )
70+ {
71+ g_AyameList.pointer[i - 1] = g_AyameList.pointer[i];
72+ }
73+
74+ g_AyameList.count--;
75+}
76+
77+
78+static VALUE Ayame_dispose( VALUE self )
79+{
80+ struct AyameData *ad = AYAME_GET_STRUCT( self );
81+ if( ad->pVoiceElement != NULL )
82+ {
83+ if( !g_AyameShutdownFlag )
84+ {
85+ ad->pVoiceElement->Release();
86+ }
87+ delete ad->pVoiceElement;
88+ ad->pVoiceElement = NULL;
89+ DeleteAyameList( ad );
90+ }
91+ return self;
92+}
93+
94+static void Ayame_release( struct AyameData *ad )
95+{
96+ if( ad->pVoiceElement != NULL )
97+ {
98+ if( !g_AyameShutdownFlag )
99+ {
100+ ad->pVoiceElement->Release();
101+ }
102+ delete ad->pVoiceElement;
103+ ad->pVoiceElement = NULL;
104+ DeleteAyameList( ad );
105+ }
106+ free( ad );
107+}
108+
109+static VALUE Ayame_allocate( VALUE klass )
110+{
111+ struct AyameData *ad = (struct AyameData *)malloc( sizeof( struct AyameData ) );
112+ ad->pVoiceElement = NULL;
113+ return Data_Wrap_Struct( klass, NULL, Ayame_release, ad );
114+}
115+
116+static VALUE Ayame_initialize( VALUE self, VALUE vfilename )
117+{
118+ struct AyameData *ad = AYAME_GET_STRUCT( self );
119+
120+ Check_Type(vfilename, T_STRING);
121+ if( strstr( RSTRING_PTR( vfilename ), ".mid" ) != NULL )
122+ {
123+ //midi
124+ ad->pVoiceElement = new CVoiceElementMidi;
125+ if( !ad->pVoiceElement->Load(RSTRING_PTR( vfilename ), 0, 0, 0) ) rb_raise( eAyameError, "%sのロードに失敗しました", vfilename );
126+ ad->pVoiceElement->SetVolume(100);
127+ }
128+ else
129+ {
130+ //ayame
131+ ad->pVoiceElement = new CVoiceElementAyame;
132+ if( !ad->pVoiceElement->Load(RSTRING_PTR( vfilename ), AYAME_LOADFLAG_GLOBAL | AYAME_LOADFLAG_STREAM, 0, 0) ) rb_raise( eAyameError, "%sのロードに失敗しました", vfilename );
133+ ad->pVoiceElement->SetVolume(100);
134+ }
135+
136+ AddAyameList( ad );
137+
138+ return self;
139+}
140+
141+static VALUE Ayame_load_from_memory( VALUE klass, VALUE vdata )
142+{
143+ struct AyameData *ad;
144+ VALUE vad;
145+
146+ Check_Type(vdata, T_STRING);
147+ vad = Ayame_allocate( klass );
148+ ad = AYAME_GET_STRUCT( vad );
149+ ad->pVoiceElement = new CVoiceElementAyame;
150+ if( !ad->pVoiceElement->Load((char*)RSTRING_PTR( vdata ), RSTRING_LEN( vdata ), AYAME_LOADFLAG_GLOBAL | AYAME_LOADFLAG_STATIC) ) rb_raise( eAyameError, "ロードに失敗しました" );
151+ ad->pVoiceElement->SetVolume(100);
152+
153+ AddAyameList( ad );
154+
155+ return vad;
156+}
157+
158+static VALUE Ayame_play( int argc, VALUE *argv, VALUE self )
159+{
160+ struct AyameData *ad = AYAME_GET_STRUCT( self );
161+
162+ if( argc < 1 || argc > 3 ) rb_raise( rb_eArgError, "wrong number of arguments (%d for %d..%d)", argc, 1, 3 );
163+
164+ if( ad->pVoiceElement == NULL ) rb_raise( eAyameError, "disposed Ayame object" );
165+ ad->pVoiceElement->Play( NUM2INT( argv[0] ) - 1, 100, argc < 2 || argv[1] == Qnil ? 0 : NUM2INT( argv[1] ) * 1000, argc < 3 || argv[2] == Qnil ? 0 : NUM2INT( argv[2] ) );
166+ ad->start_tick = GetSystemCounter();
167+ return self;
168+}
169+
170+static VALUE Ayame_stop( int argc, VALUE *argv, VALUE self )
171+{
172+ struct AyameData *ad = AYAME_GET_STRUCT( self );
173+
174+ if( argc < 0 || argc > 1 ) rb_raise( rb_eArgError, "wrong number of arguments (%d for %d..%d)", argc, 0, 1 );
175+
176+ if( ad->pVoiceElement == NULL ) rb_raise( eAyameError, "disposed Ayame object" );
177+ ad->pVoiceElement->Stop(argc == 0 || argv[0] == Qnil ? 0.0 : NUM2INT( argv[0] ) * 1000 );
178+ return self;
179+}
180+
181+static VALUE Ayame_set_volume( int argc, VALUE *argv, VALUE self )
182+//( VALUE self, VALUE vvolume, VALUE vtick )
183+{
184+ struct AyameData *ad = AYAME_GET_STRUCT( self );
185+
186+ if( argc < 1 || argc > 2 ) rb_raise( rb_eArgError, "wrong number of arguments (%d for %d..%d)", argc, 1, 2 );
187+
188+ if( ad->pVoiceElement == NULL ) rb_raise( eAyameError, "disposed Ayame object" );
189+ ad->pVoiceElement->SetVolume( NUM2INT( argv[0] ), argc < 2 || argv[1] == Qnil ? 0 : NUM2INT( argv[1] ) * 1000.0 );
190+ return self;
191+}
192+
193+static VALUE Ayame_get_volume( VALUE self )
194+{
195+ struct AyameData *ad = AYAME_GET_STRUCT( self );
196+ if( ad->pVoiceElement == NULL ) rb_raise( eAyameError, "disposed Ayame object" );
197+ return INT2NUM(ad->pVoiceElement->GetVolume());
198+}
199+
200+static VALUE Ayame_set_pan( int argc, VALUE *argv, VALUE self )
201+//( VALUE self, VALUE vpan, VALUE vtick )
202+{
203+ struct AyameData *ad = AYAME_GET_STRUCT( self );
204+
205+ if( argc < 1 || argc > 2 ) rb_raise( rb_eArgError, "wrong number of arguments (%d for %d..%d)", argc, 1, 2 );
206+
207+ if( ad->pVoiceElement == NULL ) rb_raise( eAyameError, "disposed Ayame object" );
208+ ad->pVoiceElement->SetPan( NUM2INT( argv[0] ), argc < 2 || argv[1] == Qnil ? 0 : NUM2INT( argv[1] ) * 1000.0 );
209+ return self;
210+}
211+
212+static VALUE Ayame_get_pan( VALUE self )
213+{
214+ struct AyameData *ad = AYAME_GET_STRUCT( self );
215+ if( ad->pVoiceElement == NULL ) rb_raise( eAyameError, "disposed Ayame object" );
216+ return INT2NUM(ad->pVoiceElement->GetPan ());
217+}
218+
219+static VALUE Ayame_pause( VALUE self, VALUE vtick )
220+{
221+ struct AyameData *ad = AYAME_GET_STRUCT( self );
222+ if( ad->pVoiceElement == NULL ) rb_raise( eAyameError, "disposed Ayame object" );
223+ ad->pVoiceElement->Pause( true, NUM2INT( vtick ) * 1000.0 );
224+ return self;
225+}
226+
227+static VALUE Ayame_resume( VALUE self, VALUE vtick )
228+{
229+ struct AyameData *ad = AYAME_GET_STRUCT( self );
230+ if( ad->pVoiceElement == NULL ) rb_raise( eAyameError, "disposed Ayame object" );
231+ ad->pVoiceElement->Pause( false, NUM2INT( vtick ) * 1000.0 );
232+ return self;
233+}
234+
235+static VALUE Ayame_prefetch( VALUE self )
236+{
237+ struct AyameData *ad = AYAME_GET_STRUCT( self );
238+ if( ad->pVoiceElement == NULL ) rb_raise( eAyameError, "disposed Ayame object" );
239+ ad->pVoiceElement->Prefetch();
240+ return self;
241+}
242+
243+static VALUE Ayame_predecode( VALUE self )
244+{
245+ struct AyameData *ad = AYAME_GET_STRUCT( self );
246+ if( ad->pVoiceElement == NULL ) rb_raise( eAyameError, "disposed Ayame object" );
247+ ad->pVoiceElement->Predecode();
248+ return self;
249+}
250+
251+static VALUE Ayame_IsFade( VALUE self )
252+{
253+ struct AyameData *ad = AYAME_GET_STRUCT( self );
254+ if( ad->pVoiceElement == NULL ) rb_raise( eAyameError, "disposed Ayame object" );
255+ if( ad->pVoiceElement->IsFade() )
256+ {
257+ return Qtrue;
258+ }
259+ else
260+ {
261+ return Qfalse;
262+ }
263+}
264+
265+static VALUE Ayame_IsPlay( VALUE self )
266+{
267+ struct AyameData *ad = AYAME_GET_STRUCT( self );
268+ if( ad->pVoiceElement == NULL ) rb_raise( eAyameError, "disposed Ayame object" );
269+ if( ad->pVoiceElement->IsPlaying() )
270+ {
271+ return Qtrue;
272+ }
273+ else
274+ {
275+ return Qfalse;
276+ }
277+}
278+
279+static VALUE Ayame_IsFinish( VALUE self )
280+{
281+ struct AyameData *ad = AYAME_GET_STRUCT( self );
282+ if( ad->pVoiceElement == NULL ) rb_raise( eAyameError, "disposed Ayame object" );
283+ if( ad->pVoiceElement->IsFinished() )
284+ {
285+ return Qtrue;
286+ }
287+ else
288+ {
289+ return Qfalse;
290+ }
291+}
292+
293+static VALUE Ayame_IsPause( VALUE self )
294+{
295+ struct AyameData *ad = AYAME_GET_STRUCT( self );
296+ if( ad->pVoiceElement == NULL ) rb_raise( eAyameError, "disposed Ayame object" );
297+ if( ad->pVoiceElement->IsPause() )
298+ {
299+ return Qtrue;
300+ }
301+ else
302+ {
303+ return Qfalse;
304+ }
305+}
306+
307+static VALUE Ayame_update( VALUE klass )
308+{
309+ int i;
310+
311+ for( i = 0; i < g_AyameList.count; i++ )
312+ {
313+ struct AyameData *ad = (struct AyameData *)g_AyameList.pointer[i];
314+ __int64 tick = GetSystemCounter();
315+ ad->pVoiceElement->Run((double)(tick - ad->start_tick) / (double)g_OneSecondCount * 1000.0);
316+ ad->start_tick = tick;
317+ }
318+ return Qnil;
319+}
320+
321+/*--------------------------------------------------------------------
322+ (内部関数)フレーム調整用カウンタ値取得
323+ ---------------------------------------------------------------------*/
324+static __int64 GetSystemCounter( void )
325+{
326+ __int64 time;
327+
328+ if( g_isPerformanceCounter == 1 )
329+ {
330+ QueryPerformanceCounter( (LARGE_INTEGER *)&time );
331+ return time;
332+ }
333+ else
334+ {
335+ return timeGetTime();
336+ }
337+}
338+
339+/*--------------------------------------------------------------------
340+ (内部関数)フレーム調整初期化
341+ ---------------------------------------------------------------------*/
342+static void InitSync( void )
343+{
344+ timeBeginPeriod( 1 );
345+
346+ /* パフォーマンスカウンタの秒間カウント値取得 */
347+ if( QueryPerformanceFrequency( (LARGE_INTEGER *)&g_OneSecondCount ) )
348+ {
349+ /* パフォーマンスカウンタがある場合 */
350+ g_isPerformanceCounter = 1;
351+ }
352+ else
353+ {
354+ /* パフォーマンスカウンタが無い場合 */
355+ g_isPerformanceCounter = 0;
356+ g_OneSecondCount = 1000;
357+ }
358+}
359+
360+static void Ayame_shutdown( VALUE obj )
361+{
362+ CVoiceElementAyame::m_sAyameMgr.Release();
363+ CoUninitialize();
364+ g_AyameShutdownFlag = true;
365+}
366+
367+
368+/*
369+***************************************************************
370+*
371+* Global functions
372+*
373+***************************************************************/
374+
375+LRESULT CALLBACK DummyWndProc( HWND hWnd,UINT msg,UINT wParam,LONG lParam )
376+{
377+ return DefWindowProc( hWnd, msg, wParam, lParam );
378+}
379+
380+
381+extern "C" {
382+ void Init_ayame();
383+}
384+
385+void Init_ayame()
386+{
387+ HRESULT hr;
388+ HWND hWnd;
389+ WNDCLASSEX wcex;
390+ RECT rect;
391+ HINSTANCE hInstance;
392+
393+ CoInitialize(NULL);
394+
395+ /* インスタンスハンドル取得 */
396+ hInstance = (HINSTANCE)GetModuleHandle( NULL );
397+
398+ /* ウインドウ・クラスの登録 */
399+ wcex.cbSize = sizeof( WNDCLASSEX );
400+ wcex.style = 0;
401+ wcex.lpfnWndProc = DefWindowProc;
402+ wcex.cbClsExtra = 0;
403+ wcex.cbWndExtra = 0;
404+ wcex.hInstance = hInstance;
405+ wcex.hIcon = 0;
406+ wcex.hIconSm = 0;
407+ wcex.hCursor = 0;
408+ wcex.hbrBackground = 0;
409+ wcex.lpszMenuName = NULL;
410+ wcex.lpszClassName = "Ayame";
411+
412+ if( !RegisterClassEx( &wcex ) )
413+ {
414+ rb_raise( eAyameError, "ウィンドウの初期化に失敗しました - RegusterClassEx" );
415+ }
416+
417+ hWnd = CreateWindow("Ayame", "", WS_POPUP, 0, 0, 0, 0, 0, NULL, hInstance, NULL);
418+
419+ /* 例外定義 */
420+ eAyameError = rb_define_class( "AyameError", rb_eRuntimeError );
421+
422+ if ( !CVoiceElementAyame::m_sAyameMgr.LoadDLL( hWnd, "Ayame.dll", 0 ) ) rb_raise( eAyameError, "Ayame.dllがロードできませんでした" );
423+
424+ /* Ayameクラス定義 */
425+ cAyame = rb_define_class ( "Ayame", rb_cObject );
426+
427+ /* Ayameクラスにメソッド登録*/
428+ rb_define_private_method( cAyame, "initialize", (VALUE(*)(...))Ayame_initialize, 1 );
429+ rb_define_singleton_method( cAyame, "load_from_memory", (VALUE(*)(...))Ayame_load_from_memory, 1 );
430+ rb_define_method( cAyame, "play", (VALUE(*)(...))Ayame_play, -1 );
431+ rb_define_method( cAyame, "stop", (VALUE(*)(...))Ayame_stop, -1 );
432+ rb_define_method( cAyame, "get_volume", (VALUE(*)(...))Ayame_get_volume, 0 );
433+ rb_define_method( cAyame, "set_volume", (VALUE(*)(...))Ayame_set_volume, -1 );
434+ rb_define_method( cAyame, "get_pan", (VALUE(*)(...))Ayame_get_pan, 0 );
435+ rb_define_method( cAyame, "set_pan", (VALUE(*)(...))Ayame_set_pan, -1 );
436+ rb_define_method( cAyame, "dispose", (VALUE(*)(...))Ayame_dispose, 0 );
437+ rb_define_method( cAyame, "pause", (VALUE(*)(...))Ayame_pause, 1 );
438+ rb_define_method( cAyame, "resume", (VALUE(*)(...))Ayame_resume, 1 );
439+ rb_define_method( cAyame, "prefetch", (VALUE(*)(...))Ayame_prefetch, 0 );
440+ rb_define_method( cAyame, "predecode", (VALUE(*)(...))Ayame_predecode, 0 );
441+
442+ rb_define_method( cAyame, "fading?", (VALUE(*)(...))Ayame_IsFade, 0 );
443+ rb_define_method( cAyame, "playing?", (VALUE(*)(...))Ayame_IsPlay, 0 );
444+ rb_define_method( cAyame, "finished?", (VALUE(*)(...))Ayame_IsFinish, 0 );
445+ rb_define_method( cAyame, "pausing?", (VALUE(*)(...))Ayame_IsPause, 0 );
446+
447+ rb_define_singleton_method( cAyame, "update", (VALUE(*)(...))Ayame_update, 0 );
448+
449+ /* Ayameオブジェクトを生成した時にinitializeの前に呼ばれるメモリ割り当て関数登録 */
450+ rb_define_alloc_func( cAyame, Ayame_allocate );
451+
452+ /* 終了時に実行する関数 */
453+ rb_set_end_proc( (void(*)(VALUE))Ayame_shutdown, Qnil );
454+
455+ InitSync();
456+
457+ /* Ayameオブジェクトの内部参照リスト */
458+ g_AyameList.pointer = (void**)malloc( sizeof(void*) * 16 );
459+ g_AyameList.count = 0;
460+ g_AyameList.allocate_size = 16;
461+}
--- Ayame/VoiceElement.cpp (nonexistent)
+++ Ayame/VoiceElement.cpp (revision 530)
@@ -0,0 +1,365 @@
1+/**
2+ * @file VoiceElement.cpp
3+ * @brief 単一のサウンド管理クラス
4+ * @author Sazanta
5+ */
6+
7+// インクルード
8+#include "VoiceElement.h"
9+
10+
11+INT32 CVoiceElement::m_snGlobalVol = cnVoiceElm_VolumeMax;
12+
13+
14+//! コンストラクタ
15+CVoiceElement::CVoiceElement(void)
16+{
17+ m_dwNumber = 0;
18+ m_dwUnique = 0;
19+ m_bFinishRequest = false;
20+ m_bPauseRequest = false;
21+ m_bPause = false;
22+ m_bVolumeFade = false;
23+ m_cVolume.SetNowValue(cnVoiceElm_VolumeMax);
24+ m_cPanpot.SetNowValue(cnVoiceElm_PanpotCenter);
25+#if defined(NUM_OF_SUB_VOLUME) && (NUM_OF_SUB_VOLUME > 0)
26+ for (int i = 0; i < NUM_OF_SUB_VOLUME; i++) {
27+ m_cSubVolume[i].SetNowValue(cnVoiceElm_VolumeMax);
28+ }
29+#endif
30+}
31+
32+
33+//! 定例処理
34+/**
35+ * 毎フレーム行う処理です。<br>
36+ * あまり間隔が空かないよう呼び出してください。<br>
37+ *
38+ * @param nSyncTick [in] 前回からの経過時間[tick]
39+ */
40+void CVoiceElement::Run(INT32 nSyncTick)
41+{
42+ INT32 nValue;
43+
44+ // オートパン処理
45+ if (m_cPanpot.Run(nSyncTick, nValue) == true) {
46+ m_cPanpot.SetNowValue(nValue);
47+ _SetPan(nValue);
48+ }
49+
50+ INT32 nSubVol = cnVoiceElm_VolumeMax;
51+ bool bSubChange = false;
52+#if defined(NUM_OF_SUB_VOLUME) && (NUM_OF_SUB_VOLUME > 0)
53+ // サブボリュームフェード処理
54+ for (int i = 0; i < NUM_OF_SUB_VOLUME; i++) {
55+ if (m_cSubVolume[i].Run(nSyncTick, nValue) == true) {
56+ nSubVol *= nValue;
57+ nSubVol /= cnVoiceElm_VolumeRange;
58+ m_cSubVolume[i].SetNowValue(nValue);
59+ bSubChange = true;
60+ }
61+ }
62+#endif
63+
64+ // メインボリュームフェード処理
65+ if (m_cVolume.Run(nSyncTick, nValue) == true) {
66+ _SetVolume(nValue * m_snGlobalVol * nSubVol / (cnVoiceElm_VolumeRange * cnVoiceElm_VolumeRange));
67+ if (m_bVolumeFade == true) {
68+ m_cVolume.SetNowValue(nValue);
69+ }
70+ if (m_cVolume.IsFade() == false) {
71+ // フェード終了
72+ if (m_bFinishRequest == true) {
73+ Stop();
74+ m_bFinishRequest = false;
75+ } else if (m_bPauseRequest == true) {
76+ _Pause();
77+ m_bPauseRequest = false;
78+ m_bPause = true;
79+ }
80+ m_bVolumeFade = false;
81+ }
82+ } else {
83+ if (bSubChange != false) {
84+ _SetVolume(nValue * m_snGlobalVol * nSubVol / (cnVoiceElm_VolumeRange * cnVoiceElm_VolumeRange));
85+ }
86+ }
87+}
88+
89+
90+//! データの解放
91+/**
92+ * データの解放を行います。<br>
93+ */
94+void CVoiceElement::Release(void)
95+{
96+ Stop();
97+ _Release();
98+}
99+
100+
101+//! 再生終了チェック
102+/**
103+ * 再生が終了しているかどうかを取得します。<br>
104+ *
105+ * @return 終了している場合はtrueを返す
106+ */
107+bool CVoiceElement::IsFinished(void) const
108+{
109+ if (_IsFinished() == true) {
110+ return true;
111+ }
112+ if (m_bFinishRequest == true && IsFade() == false) {
113+ return true;
114+ }
115+
116+ return false;
117+}
118+
119+
120+//! フェードの中断
121+void CVoiceElement::AbortFade(void)
122+{
123+ if (IsFade() == true) {
124+ m_cVolume.ResetTime();
125+ m_bVolumeFade = false;
126+ }
127+}
128+
129+
130+void CVoiceElement::InternalFade(INT32 nVolume, INT32 nTick, INT32 nStartVolume)
131+{
132+ INT32 nSave = m_cVolume.GetNowValue();
133+ SetVolume(nVolume, nTick, nStartVolume);
134+ m_cVolume.SetNowValue(nSave);
135+ m_bVolumeFade = false;
136+}
137+
138+
139+INT32 CVoiceElement::InternalGetVolume(void) const
140+{
141+ return (m_cVolume.IsFade() == true && m_bVolumeFade == false)? m_cVolume.GetCalcValue() : m_cVolume.GetNowValue();
142+}
143+
144+
145+INT32 CVoiceElement::CalculateSubVolume(void) const
146+{
147+ INT32 nSubVol = cnVoiceElm_VolumeMax;
148+#if defined(NUM_OF_SUB_VOLUME) && (NUM_OF_SUB_VOLUME > 0)
149+ for (int i = 0; i < NUM_OF_SUB_VOLUME; i++) {
150+ nSubVol *= m_cSubVolume[i].GetNowValue() / cnVoiceElm_VolumeRange;
151+ }
152+#endif
153+
154+ return nSubVol;
155+}
156+
157+
158+//! ボリュームの取得
159+/**
160+ * 現在のボリュームを取得します。<br>
161+ *
162+ * @return ボリューム値
163+ */
164+INT32 CVoiceElement::GetVolume(void) const
165+{
166+ return m_cVolume.GetNowValue();
167+}
168+
169+
170+//! ボリュームの設定
171+/**
172+ * ボリュームの設定を行います。<br>
173+ *
174+ * @param nVolume [in] ボリューム(0 〜 100)
175+ * @param nTick [in] 遷移時間[tick]
176+ * @param nStartVolume [in] スタートボリューム(省略した場合は現在値を参照)
177+ */
178+void CVoiceElement::SetVolume(INT32 nVolume, INT32 nTick, INT32 nStartVolume)
179+{
180+ VolumeClamp(nVolume);
181+ m_bVolumeFade = false;
182+ if (nTick > 0) {
183+ if (nStartVolume < 0) {
184+ nStartVolume = InternalGetVolume();
185+ }
186+ m_cVolume.SetParam(nTick, nStartVolume, nVolume);
187+ m_bVolumeFade = true;
188+ nVolume = nStartVolume;
189+ } else {
190+ m_cVolume.ResetTime();
191+ }
192+
193+ m_cVolume.SetNowValue(nVolume);
194+ _SetVolume(nVolume * m_snGlobalVol * CalculateSubVolume() / (cnVoiceElm_VolumeRange * cnVoiceElm_VolumeRange));
195+}
196+
197+
198+//! サブボリュームの取得
199+/**
200+ * サブボリューム値の取得を行います。
201+ *
202+ * @param nChannel [in] サブボリュームチャンネル
203+ *
204+ * @return ボリューム値
205+ */
206+INT32 CVoiceElement::GetSubVolume(UINT32 nChannel) const
207+{
208+#if defined(NUM_OF_SUB_VOLUME) && (NUM_OF_SUB_VOLUME > 0)
209+ return (nChannel < NUM_OF_SUB_VOLUME)? m_cSubVolume[nChannel].GetNowValue() : cnVoiceElm_VolumeMax;
210+#else
211+ return cnVoiceElm_VolumeMax;
212+#endif
213+}
214+
215+
216+//! サブボリュームの設定
217+/**
218+ * サブボリューム値の設定を行います。
219+ *
220+ * @param nChannel [in] サブボリュームチャンネル
221+ * @param nVolume [in] ボリューム
222+ * @param nTick [in] 遷移時間[tick]
223+ * @param nStartVolume [in] スタートボリューム(省略した場合は現在値を参照)
224+ */
225+void CVoiceElement::SetSubVolume(UINT32 nChannel, INT32 nVolume, INT32 nTick, INT32 nStartVolume)
226+{
227+#if defined(NUM_OF_SUB_VOLUME) && (NUM_OF_SUB_VOLUME > 0)
228+ if (nChannel >= NUM_OF_SUB_VOLUME) return;
229+
230+ VolumeClamp(nVolume);
231+ if (nTick > 0) {
232+ if (nStartVolume < 0) {
233+ nStartVolume = (m_cSubVolume[nChannel].IsFade() == true)? m_cSubVolume[nChannel].GetCalcValue() : m_cSubVolume[nChannel].GetNowValue();
234+ }
235+ m_cSubVolume[nChannel].SetParam(nTick, nStartVolume, nVolume);
236+ nVolume = nStartVolume;
237+ } else {
238+ m_cSubVolume[nChannel].ResetTime();
239+ }
240+ m_cSubVolume[nChannel].SetNowValue(nVolume);
241+ ReflectMasterVolume();
242+#endif
243+}
244+
245+
246+//! パンの取得
247+/**
248+ * 現在のパンを取得します。<br>
249+ *
250+ * @return パン値
251+ */
252+INT32 CVoiceElement::GetPan(void) const
253+{
254+ return m_cPanpot.GetNowValue();
255+}
256+
257+
258+//! パンの設定
259+/**
260+ * パンの設定を行います。<br>
261+ *
262+ * @param nPan [in] パン
263+ * @param nTick [in] 遷移時間
264+ * @param nStartPan [in] スタートパン(省略した場合は現在値を参照)
265+ */
266+void CVoiceElement::SetPan(INT32 nPan, INT32 nTick, INT32 nStartPan)
267+{
268+ nPan = (nPan < cnVoiceElm_PanpotMaxL)? cnVoiceElm_PanpotMaxL : ((nPan > cnVoiceElm_PanpotMaxR)? cnVoiceElm_PanpotMaxR : nPan);
269+ if (nTick > 0) {
270+ if (nStartPan < cnVoiceElm_PanpotMaxL || nStartPan > cnVoiceElm_PanpotMaxR) {
271+ nStartPan = m_cPanpot.GetNowValue();
272+ }
273+ m_cPanpot.SetParam(nTick, nStartPan, nPan);
274+ nPan = nStartPan;
275+ } else {
276+ m_cPanpot.ResetTime();
277+ }
278+ m_cPanpot.SetNowValue(nPan);
279+ _SetPan(nPan);
280+}
281+
282+
283+//! 再生
284+/**
285+ * 再生を行います。<br>
286+ * nLoopに0を指定すると、1回演奏して終了します。<br>
287+ * nLoopInSampleを0以外に設定すると、ループする際のループ開始ポイントを設定できます。<br>
288+ * 単位はサンプルです。<br>
289+ *
290+ * @param nLoop [in] ループ回数(LOOP_INFINITYで無限ループ)
291+ * @param nVolume [in] ボリューム
292+ * @param nFadeInTick [in] フェードイン時間[tick]
293+ * @param nLoopInSample [in] ループインサンプル
294+ */
295+void CVoiceElement::Play(UINT32 nLoop, INT32 nVolume, INT32 nFadeInTick, UINT32 nLoopInSample)
296+{
297+ Stop();
298+ SetVolume(nVolume, nFadeInTick, 0);
299+ m_cVolume.SetNowValue(nVolume);
300+ m_bVolumeFade = false;
301+
302+ _Play(nLoop, nLoopInSample);
303+}
304+
305+
306+//! 停止
307+/**
308+ * 停止します。<br>
309+ * フェードアウト時間が0でない場合、フェード終了後停止します。<br>
310+ *
311+ * @param fFadeOutTime [in] フェードアウト時間
312+ */
313+void CVoiceElement::Stop(INT32 nFadeOutTick)
314+{
315+ m_bPauseRequest = false;
316+ if (nFadeOutTick > 0 && m_bPause == false) {
317+ InternalFade(0, nFadeOutTick);
318+ m_bFinishRequest = true;
319+ } else {
320+ AbortFade();
321+ m_bPause = false;
322+ _Stop();
323+ }
324+}
325+
326+
327+//! 一時停止
328+/**
329+ * 一時停止します。<br>
330+ *
331+ * @param bPause [in] ポーズする場合はtrue、ポーズを解除する場合はfalse
332+ * @param fFadeTime [in] フェード時間
333+ */
334+void CVoiceElement::Pause(bool bPause, INT32 nFadeTick)
335+{
336+ if (bPause == true) {
337+ // ポーズする
338+ if (m_bPauseRequest == false && IsPause() == false) {
339+ m_bFinishRequest = false;
340+ if (nFadeTick > 0) {
341+ InternalFade(0, nFadeTick);
342+ m_bPauseRequest = true;
343+ } else {
344+ AbortFade();
345+ _Pause();
346+ m_bPause = true;
347+ }
348+ }
349+ } else {
350+ // ポーズ解除する
351+ if (m_bPauseRequest == true || IsPause() == true) {
352+ if (IsPause() == true) {
353+ m_bPause = false;
354+ InternalFade(m_cVolume.GetNowValue(), nFadeTick, 0);
355+ _Pause();
356+ } else {
357+ InternalFade(m_cVolume.GetNowValue(), nFadeTick);
358+ }
359+ m_bPauseRequest = false;
360+ }
361+ }
362+}
363+
364+
365+/* Bottom of VoiceElement.cpp */
--- Ayame/Ayame.h (nonexistent)
+++ Ayame/Ayame.h (revision 530)
@@ -0,0 +1,69 @@
1+/**
2+*/
3+
4+#ifndef ___AYAME_H___
5+#define ___AYAME_H___
6+
7+
8+//====================================================================
9+// INCLUDE
10+//====================================================================
11+#include <tchar.h>
12+#include <dsound.h>
13+
14+
15+//====================================================================
16+// DEFINE
17+//====================================================================
18+#define AYAME_LOOP_INFINITY (0xFFFFFFFF) ///< 無限ループ
19+#define AYAME_LOADFLAG_GLOBAL (1<<0)
20+#define AYAME_LOADFLAG_STREAM (0<<1)
21+#define AYAME_LOADFLAG_STATIC (1<<1)
22+
23+
24+//====================================================================
25+// TYPEDEF
26+//====================================================================
27+typedef bool (*AYAME_INITIALIZE_PROC)( HWND hWnd, void **ppDirectSound ); ///< ドライバー初期化
28+typedef void (*AYAME_UNINITIALIZE_PROC)( void ); ///< ドライバー解放
29+typedef bool (*AYAME_GETERROR_PROC)( TCHAR *pErrStr, unsigned long Size ); ///< エラー取得
30+typedef class CAyame *(*AYAME_CREATE_FROM_FILE_PROC)( const TCHAR *pFileName, unsigned long Start, unsigned long Size, unsigned long Flag ); ///< ドライバーからオブジェクト取得
31+typedef class CAyame *(*AYAME_CREATE_FROM_MEMORY_PROC)( const void *pData, unsigned long Size, unsigned long Flag ); ///< ドライバーからオブジェクト取得
32+typedef class CAyame *(*AYAME_CREATE_FROM_URL_PROC)( const TCHAR *pUrl, unsigned long Start, unsigned long Size, unsigned long Flag ); ///< ドライバーからオブジェクト取得
33+
34+
35+//====================================================================
36+/**
37+ @brief 再生用クラス
38+
39+ DLL用に純粋仮想関数だけの中身のないクラスです
40+*/
41+//====================================================================
42+class CAyame
43+{
44+protected:
45+ virtual ~CAyame(){} ///< デストラクタ
46+public:
47+ virtual bool __stdcall IsEmptyQueue( void ) = 0; ///< キューに登録があるかどうか
48+ virtual bool __stdcall IsReady( void ) const = 0; ///< 初期化完了済みか?
49+ virtual bool __stdcall IsNotDecoder( void ) const = 0; ///< デコーダが存在するかどうか?
50+ virtual bool __stdcall IsPlayStarted( void ) const = 0; ///< 再生開始チェック
51+ virtual bool __stdcall IsPlay( void ) const = 0; ///< 再生チェック
52+ virtual bool __stdcall IsPause( void ) const = 0; ///< 一時停止中チェック
53+ virtual bool __stdcall Prefetch( void ) = 0; ///< プリフェッチ
54+ virtual bool __stdcall Predecode( void ) = 0; ///< プリデコード
55+ virtual bool __stdcall Combine( CAyame *pAyame ) = 0; ///< 連結
56+ virtual bool __stdcall Play( unsigned long nLoopCount = 0, unsigned long nLoopInSample = 0, unsigned long nStartPos = 0 ) = 0; ///< 再生
57+ virtual bool __stdcall Stop( void ) = 0; ///< 停止
58+ virtual bool __stdcall Pause( void ) = 0; ///< 一時停止
59+ virtual bool __stdcall SetVolume( float fParam ) = 0; ///< ボリューム設定
60+ virtual bool __stdcall SetPan( float fParam ) = 0; ///< パン設定
61+ virtual bool __stdcall SetFrequencyRate( float fParam ) = 0; ///< 周波数設定
62+ virtual bool __stdcall Release( void ) = 0; ///< 解放
63+ virtual bool __stdcall AddRef( void ) = 0; ///< 参照カウントインクリメント
64+ virtual unsigned long __stdcall GetPlayingPoint( void ) = 0; ///< おおよその再生位置の取得
65+ virtual unsigned long __stdcall GetTotalSample( void ) = 0; ///< トータルのサンプル数の取得
66+};
67+
68+
69+#endif // ___AYAME_H___
--- Ayame/VoiceElementAyame.h (nonexistent)
+++ Ayame/VoiceElementAyame.h (revision 530)
@@ -0,0 +1,95 @@
1+/**
2+ * @file VoiceElementAyame.h
3+ * @brief 単一のサウンド管理クラス
4+ * @author Sazanta
5+ */
6+#ifndef __VOICEELEMENTAYAME_H__
7+#define __VOICEELEMENTAYAME_H__
8+
9+// インクルード
10+#include "AyameManager.h"
11+#include "VoiceElement.h"
12+
13+
14+//! CVoiceElementAyameクラス
15+/**
16+ * このクラスは、Ayameを使用したCVoiceElement操作を提供する派生クラスです。<br>
17+ */
18+class CVoiceElementAyame : public CVoiceElement
19+{
20+ public:
21+ static CAyameManager m_sAyameMgr;
22+
23+ protected:
24+ CAyame* m_pAyame; //!< Ayameインスタンス
25+
26+ void _Release(void) {
27+ if (m_pAyame != NULL) {
28+ m_pAyame->Release();
29+ m_pAyame = NULL;
30+ }
31+ }
32+ void _SetPan(INT32 nPan) {
33+ if (m_pAyame != NULL) {
34+ m_pAyame->SetPan((FLOAT)nPan * 100.0f * (1.0f / 128.0f));
35+ }
36+ }
37+ void _SetVolume(INT32 nVolume) {
38+ if (m_pAyame != NULL) {
39+ m_pAyame->SetVolume((FLOAT)nVolume * 100.0f * (1.0f / 128.0f));
40+ }
41+ }
42+ void _Pause(void) {
43+ if (m_pAyame != NULL) {
44+ m_pAyame->Pause();
45+ }
46+ }
47+ bool _Load(const char* pSoundData, UINT32 nDataSize, UINT32 nFlag) {
48+ m_pAyame = m_sAyameMgr.CreateInstanceFromMemory(pSoundData, nDataSize, nFlag);
49+ return (m_pAyame != NULL);
50+ }
51+ bool _Load(const TCHAR* pFileName, UINT32 nFlag, UINT32 nOffset, UINT32 nDataSize) {
52+ m_pAyame = m_sAyameMgr.CreateInstanceFromFile((TCHAR*)pFileName, nOffset, nDataSize, nFlag);
53+ return (m_pAyame != NULL);
54+ }
55+ bool _IsPlaying(void) const {
56+ if (m_pAyame == NULL) return false;
57+ return m_pAyame->IsPlay();
58+ }
59+ bool _IsFinished(void) const {
60+ if (m_pAyame == NULL) return true;
61+ return (IsPause() == false && m_pAyame->IsPlay() == false);
62+ }
63+ void _Play(UINT32 nLoop, UINT32 nLoopInSample = 0, UINT32 nStartPos = 0) {
64+ if (m_pAyame != NULL) {
65+ m_pAyame->Play(nLoop, nLoopInSample, nStartPos);
66+ }
67+ }
68+ void _Stop(void){
69+ if (m_pAyame != NULL) {
70+ m_pAyame->Stop();
71+ }
72+ }
73+ void _Prefetch(void){
74+ if (m_pAyame != NULL) {
75+ m_pAyame->Prefetch();
76+ }
77+ }
78+ void _Predecode(void){
79+ if (m_pAyame != NULL) {
80+ m_pAyame->Predecode();
81+ }
82+ }
83+
84+ public:
85+ CVoiceElementAyame(void) {
86+ m_pAyame = NULL;
87+ }
88+ virtual ~CVoiceElementAyame(void) {
89+// _Release();
90+ }
91+};
92+
93+
94+#endif // __VOICEELEMENTAYAME_H__
95+/* Bottom of VoiceElementAyame.h */
--- Ayame/midi.cpp (nonexistent)
+++ Ayame/midi.cpp (revision 530)
@@ -0,0 +1,897 @@
1+/**
2+ * @brief MIDI再生クラス
3+ * @file midi.cpp
4+ * @author sazanta
5+ */
6+#include "midi.h"
7+
8+#pragma comment (lib, "winmm.lib")
9+
10+
11+//! MIDIイベント保持クラス
12+class CMidiEvent
13+{
14+ public:
15+ CMidiEvent* lpNext; // 次のイベントへのポインタ
16+ unsigned long dwDelta; // デルタタイム
17+ unsigned char state; // ステータスバイト
18+ unsigned char data1; // 第一データバイト
19+ unsigned char data2; // 第二データバイト
20+ unsigned char type; // タイプ
21+ unsigned char* lpData; // 可変長データ
22+ long nData; // データ長
23+
24+ CMidiEvent(void) {
25+ lpNext = NULL;
26+ lpData = NULL;
27+ nData = 0;
28+ }
29+ ~CMidiEvent(void) {
30+ delete[] lpData;
31+ }
32+};
33+
34+
35+//! コンストラクタ
36+CMidi::CMidi(void)
37+{
38+ m_pHeader = NULL;
39+ m_nAttribute = 0;
40+ m_nTime = 120 * 1000;
41+ m_nTimeBias = 1000;
42+ m_nTempo = 500000;
43+ m_nTimerID = 0;
44+ m_hMidiOut = NULL;
45+ for (int i = 0; i < 16; i++) {
46+ m_nPanpot[i] = 64;
47+ m_nVolume[i] = 100;
48+ }
49+ m_nMasterVolume = 256;
50+ m_nMuteFlag = 0;
51+ m_nMasterPanpot = 64;
52+
53+ // クリティカルセクションの生成
54+ ::InitializeCriticalSection(&m_stCriticalSection);
55+ ::ZeroMemory(&m_stQue, sizeof(m_stQue));
56+ m_hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
57+ m_bEnd = false;
58+ // 処理スレッド生成
59+ m_hThread = ::CreateThread(NULL, 0, ThreadProc, this, 0, &m_nThreadId);
60+}
61+
62+
63+//! デストラクタ
64+CMidi::~CMidi(void)
65+{
66+ // クリティカルセクションの破棄
67+ ::DeleteCriticalSection(&m_stCriticalSection);
68+ ::CloseHandle(m_hEvent);
69+}
70+
71+
72+//! MIDIデータの解放
73+void CMidi::Release(void)
74+{
75+ ::EnterCriticalSection(&m_stCriticalSection);
76+ m_bEnd = true;
77+ ::SetEvent(m_hEvent);
78+ ::LeaveCriticalSection( &m_stCriticalSection );
79+ ::WaitForSingleObject(m_hThread, INFINITE);
80+}
81+
82+
83+//! MIDIファイルのアタッチ
84+/**
85+ * MIDIファイルのアタッチを行います。
86+ *
87+ * @param pFileName [in] SMFファイルパス
88+ * @param nOfs [in] SMFファイルオフセット
89+ * @param nSize [in] SMFファイルサイズ(0の場合は自動計算)
90+ *
91+ * @return 正しくアタッチできた場合はtrueを返す
92+ */
93+bool CMidi::AttachMidiFile(const TCHAR* pFileName, unsigned int nOfs, unsigned int nSize)
94+{
95+ EVENT_QUE Que = { EVT_LOAD };
96+
97+ size_t nLen;
98+#ifdef _UNICODE
99+ nLen = (wcslen(pFileName) + 1) * 2;
100+#else
101+ nLen = strlen(pFileName) + 1;
102+#endif
103+ Que.Data_Load.pData = new char[nLen];
104+ ::CopyMemory(Que.Data_Load.pData, pFileName, nLen);
105+ Que.Data_Load.nSize = nSize;
106+ Que.Data_Load.nStart = nOfs;
107+ Que.Data_Load.nType = 1;
108+
109+ // キューに追加
110+ return AddQue(&Que);
111+}
112+
113+
114+//! MIDIデータのアタッチ
115+/**
116+ * MIDIデータのアタッチを行います。
117+ * 関数を抜けた後は、データを削除しても構いません。
118+ *
119+ * @param pData [in] SMFデータポインタ
120+ * @param nSize [in] SMFデータサイズ
121+ *
122+ * @return 正しくアタッチできた場合はtrueを返す
123+ */
124+bool CMidi::AttachMidiData(const unsigned char* pData, unsigned int nSize)
125+{
126+ EVENT_QUE Que = { EVT_LOAD };
127+
128+ Que.Data_Load.pData = new char[nSize];
129+ if (Que.Data_Load.pData == NULL) return false;
130+ ::CopyMemory(Que.Data_Load.pData, pData, nSize);
131+ Que.Data_Load.nSize = nSize;
132+ Que.Data_Load.nType = 0;
133+
134+ // キューに追加
135+ return AddQue(&Que);
136+}
137+
138+
139+//! 再生
140+bool CMidi::Play(unsigned long nLoop)
141+{
142+ EVENT_QUE Que = { EVT_PLAY };
143+
144+ Que.Data_Play.nStartPos = 0;
145+ Que.Data_Play.nLoopCount = nLoop;
146+
147+ // キューに追加
148+ return AddQue(&Que);
149+}
150+
151+
152+//! 停止
153+bool CMidi::Stop(void)
154+{
155+ EVENT_QUE Que = { EVT_STOP };
156+
157+ // キューに追加
158+ return AddQue(&Que);
159+}
160+
161+
162+//! ポーズ
163+bool CMidi::Pause(void)
164+{
165+ EVENT_QUE Que = { EVT_PAUSE };
166+
167+ // キューに追加
168+ return AddQue(&Que);
169+}
170+
171+
172+//! ミュートフラグの設定
173+/**
174+ * @param nFlag [in] ミュートするチャンネルの論理和
175+ *
176+ * @return 設定を行う前の値
177+ */
178+unsigned short CMidi::SetMuteFlag(unsigned short nFlag)
179+{
180+ unsigned short nOld = m_nMuteFlag;
181+ if (m_nMuteFlag != nFlag) {
182+ m_nMuteFlag = nFlag;
183+ m_nAttr_UpdateV = 1;
184+ }
185+
186+ return nOld;
187+}
188+
189+
190+//! ミュートフラグの設定
191+unsigned short CMidi::SetMuteFlag(unsigned int nChannel, bool bFlag)
192+{
193+ unsigned short nOld = m_nMuteFlag;
194+ if (nChannel < 16) {
195+ if (bFlag == false) m_nMuteFlag &= ~(1<<nChannel);
196+ else m_nMuteFlag |= (1<<nChannel);
197+ }
198+ if (m_nMuteFlag != nOld) {
199+ m_nAttr_UpdateV = 1;
200+ }
201+
202+ return nOld;
203+}
204+
205+
206+//! MIDIヘッダのチェック
207+/**
208+ * @return MIDIヘッダが正しければtrueを返す
209+ */
210+bool CMidi::CheckMidiHeader(const unsigned char* pData)
211+{
212+ if (pData[0] != 'M' || pData[1] != 'T' || pData[2] != 'h' || pData[3] != 'd') {
213+ return false;
214+ }
215+ pData += 4;
216+ if (pData[0] != 0x00 || pData[1] != 0x00 || pData[2] != 0x00 || pData[3] != 0x06) {
217+ return false;
218+ }
219+
220+ return true;
221+}
222+
223+
224+bool CMidi::AddQue(EVENT_QUE* pQue)
225+{
226+ // クリティカルセクションに入る
227+ ::EnterCriticalSection(&m_stCriticalSection);
228+ if (m_bEnd == true) {
229+ // クリティカルセクションから抜ける
230+ ::LeaveCriticalSection( &m_stCriticalSection );
231+ return true;
232+ }
233+
234+ bool bRet = false;
235+ int nSlot = 0;
236+ for (; ((nSlot < EVT_MAX) && (m_stQue[nSlot].bUse == true)); nSlot++) {
237+ if (m_stQue[nSlot].EventType == pQue->EventType) {
238+ // 先発の同じ要求は却下する
239+ if (m_stQue[nSlot].EventType == EVT_LOAD && m_stQue[nSlot].Data_Load.nType != 0) {
240+ delete[] m_stQue[nSlot].Data_Load.pData;
241+ }
242+ ::MoveMemory(&m_stQue[nSlot], &m_stQue[nSlot + 1], sizeof(EVENT_QUE) * (EVT_MAX - (nSlot + 1)));
243+ m_stQue[EVT_MAX - 1].bUse = false;
244+ nSlot--;
245+ }
246+ }
247+ // キューは一杯ではない
248+ if (nSlot != EVT_MAX) {
249+ // データコピー
250+ ::CopyMemory(&m_stQue[nSlot], pQue, sizeof(EVENT_QUE));
251+ // 使用中フラグON
252+ m_stQue[nSlot].bUse = true;
253+ // プレイキューの場合は、フラグを立てる
254+ if (pQue->EventType == EVT_PLAY) m_nIsPlayQue = true;
255+ // イベントON
256+ ::SetEvent(m_hEvent);
257+ // 処理成功
258+ bRet = true;
259+ }
260+
261+ // クリティカルセクションから抜ける
262+ ::LeaveCriticalSection(&m_stCriticalSection);
263+
264+ return bRet;
265+}
266+
267+
268+//! データの解放
269+void CMidi::_Release(void)
270+{
271+ _Stop();
272+ if (m_pHeader != NULL) {
273+ ReleaseMain(m_pHeader);
274+ m_pHeader = NULL;
275+ }
276+}
277+
278+
279+bool CMidi::_AttachMidiFile(const char* pFileName, unsigned int nOfs, unsigned int nSize)
280+{
281+ HANDLE hFile = ::CreateFile((LPCTSTR)pFileName, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
282+ if (hFile == INVALID_HANDLE_VALUE) {
283+ return false;
284+ }
285+ if (nSize == 0) {
286+ nSize = ::GetFileSize(hFile, NULL);
287+ if (nSize <= nOfs) {
288+ ::CloseHandle(hFile);
289+ return false;
290+ }
291+ nSize -= nOfs;
292+ }
293+
294+ char* pBuff = new char[nSize];
295+ if (pBuff == NULL) {
296+ ::CloseHandle(hFile);
297+ return false;
298+ }
299+
300+ if (::SetFilePointer(hFile, nOfs, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
301+ delete[] pBuff;
302+ ::CloseHandle(hFile);
303+ return false;
304+ }
305+ unsigned long nReadSize;
306+ ::ReadFile(hFile, pBuff, nSize, &nReadSize, NULL);
307+ ::CloseHandle(hFile);
308+ if (nReadSize != nSize) {
309+ delete[] pBuff;
310+ return false;
311+ }
312+ bool bRet = _AttachMidiData((const unsigned char*)pBuff, nSize);
313+ delete[] pBuff;
314+
315+ return bRet;
316+}
317+
318+
319+bool CMidi::_AttachMidiData(const unsigned char* pData, unsigned int nSize)
320+{
321+ if (nSize <= 14 || CheckMidiHeader(pData) == false) {
322+ // データ不正
323+ return false;
324+ }
325+
326+ _Release();
327+ unsigned char* pTmpData = (unsigned char*)(pData + 8);
328+ unsigned short nFormat = ((unsigned short)pTmpData[0] << 8) | pTmpData[1];
329+ pTmpData += 2;
330+
331+ unsigned short nTrack = ((unsigned short)pTmpData[0] << 8) | pTmpData[1];
332+ pTmpData += 2;
333+
334+ unsigned short nTime = ((unsigned short)pTmpData[0] << 8) | pTmpData[1];
335+ if (nTime == 0 || nTrack > 128) {
336+ // データ不正
337+ return false;
338+ }
339+ pTmpData += 2;
340+ nSize -= 14;
341+
342+ CMidiEvent* lpaEvent[128];
343+ for (int i = 0; i < nTrack; i++) {
344+ if (ReadTrack(&pTmpData, &lpaEvent[i], nSize) == false) {
345+ // トラック読み込み失敗
346+ for (int j = 0; j < (i + 1); j++) {
347+ ReleaseMain(lpaEvent[j]);
348+ }
349+ return false;
350+ }
351+ }
352+
353+ if (nFormat == 1 && nTrack != 1) {
354+ if ((m_pHeader = Marge(lpaEvent, nTrack)) == NULL) {
355+ return false;
356+ }
357+ } else {
358+ m_pHeader = lpaEvent[0];
359+ }
360+ m_nTempo = 500000;
361+ m_nTime = nTime * 1000;
362+ m_nTotalTime = CalcTotalTime();
363+
364+ return true;
365+}
366+
367+
368+bool CMidi::_Play(unsigned int nLoop)
369+{
370+ if (m_pNowPoint != NULL || m_pHeader == NULL) {
371+ return false;
372+ }
373+ MMRESULT mr;
374+ if (m_hMidiOut == NULL) {
375+ mr = midiOutOpen(&m_hMidiOut, MIDIMAPPER, 0, 0, CALLBACK_NULL);
376+ if (mr != MMSYSERR_NOERROR) {
377+ return false;
378+ }
379+ }
380+ TIMECAPS stCaps;
381+ mr = timeGetDevCaps(&stCaps, sizeof(TIMECAPS));
382+ if (mr != TIMERR_NOERROR) {
383+ return false;
384+ }
385+ m_pNowPoint = m_pHeader;
386+ m_nTempo = 500000; // テンポのデフォルト値
387+ m_nNextTime = 0;
388+ m_nPrevTime = timeGetTime();
389+ m_nNowTime = 0;
390+ m_nNowTimeRest = 0;
391+ m_nTimeRest = 0;
392+ m_nLoop = nLoop;
393+ for (int i = 0; i < 16; i++) {
394+ m_nVolume[i] = 100;
395+ }
396+ m_nAttr_UpdateV = 1;
397+ m_nAttr_UpdateP = 1;
398+ m_nIsPlayQue = 0;
399+ m_nTimerID = timeSetEvent(stCaps.wPeriodMin, 0, TimeCallbackProc, (unsigned long)this, TIME_PERIODIC);
400+ if (m_nTimerID == NULL) {
401+ return false;
402+ }
403+
404+ return true;
405+}
406+
407+
408+bool CMidi::_Stop(void)
409+{
410+ if (m_nTimerID != 0) {
411+ timeKillEvent(m_nTimerID);
412+ m_nTimerID = 0;
413+ }
414+ if (m_hMidiOut != NULL) {
415+ midiOutReset(m_hMidiOut); // 再生中の音を消す
416+ midiOutClose(m_hMidiOut);
417+ m_hMidiOut = NULL;
418+ }
419+ m_nNowTime = 0;
420+ m_pNowPoint = NULL;
421+ m_nAttr_Pause = 0;
422+
423+ return true;
424+}
425+
426+
427+void CMidi::_Pause(void)
428+{
429+ if (m_pNowPoint != NULL) {
430+ m_nAttr_Pause = (m_nAttr_Pause == 0)? 1 : 0;
431+ midiOutReset(m_hMidiOut); // 再生中の音を消す
432+ m_nAttr_UpdateV = 1;
433+ }
434+}
435+
436+
437+//! イベントクラスの解放
438+void CMidi::ReleaseMain(CMidiEvent* pEvent)
439+{
440+ while (pEvent != NULL) {
441+ CMidiEvent* pTmp = pEvent;
442+ pEvent = pEvent->lpNext;
443+ delete pTmp;
444+ }
445+}
446+
447+
448+//! トラックの解析
449+bool CMidi::ReadTrack(unsigned char** ppData, CMidiEvent** lplpEvent, unsigned int& nSize)
450+{
451+ unsigned char* pData = *ppData;
452+ unsigned char statePrev = 0; // 前のイベントのステータスバイト
453+ CMidiEvent* lpEvent;
454+
455+ if (pData[0] != 'M' || pData[1] != 'T' || pData[2] != 'r' || pData[3] != 'k' || nSize <= 8) {
456+ // データ不正
457+ *lplpEvent = NULL;
458+ return false;
459+ }
460+ nSize -= 4 + 4;
461+ unsigned long nLen = pData[7] | ((unsigned long)pData[6] << 8) | ((unsigned long)pData[5] << 16) | ((unsigned long)pData[4] << 24);
462+ if (nLen > nSize) {
463+ // データ不正
464+ *lplpEvent = NULL;
465+ return false;
466+ }
467+ pData += 4 + 4;
468+
469+ lpEvent = new CMidiEvent(); // 最初のイベントのメモリを確保
470+ *lplpEvent = lpEvent; // lplpEventは常に最初のイベントを指す
471+ while (1) {
472+ // デルタタイムを読み込む
473+ if ((pData = ReadDelta(pData, lpEvent->dwDelta, nSize)) == NULL) {
474+ // データ不正
475+ return false;
476+ }
477+
478+ lpEvent->state = *pData;
479+ if ((lpEvent->state & 0x80) == 0) { // ランニングステータスか
480+ lpEvent->state = statePrev; // 一つ前のイベントのステータスバイトを代入
481+ } else {
482+ pData++;
483+ nSize--;
484+ }
485+
486+ switch (lpEvent->state & 0xf0) { // ステータスバイトを基にどのイベントか判別
487+ case 0x80:
488+ case 0x90:
489+ case 0xa0:
490+ case 0xb0:
491+ case 0xe0:
492+ lpEvent->data1 = *pData++;
493+ lpEvent->data2 = *pData++;
494+ nSize -= 2;
495+ break;
496+ case 0xc0:
497+ case 0xd0:
498+ lpEvent->data1 = *pData++;
499+ lpEvent->data2 = 0;
500+ nSize--;
501+ break;
502+
503+ case 0xf0:
504+ unsigned long dw;
505+ if (lpEvent->state == 0xf0 || lpEvent->state == 0xf7) {
506+ // SysExイベント
507+ if ((pData = ReadDelta(pData, dw, nSize)) == NULL) {
508+ return false;
509+ }
510+ if (lpEvent->state == 0xf0) dw++;
511+ lpEvent->nData = dw;
512+ lpEvent->lpData = new unsigned char[dw];
513+ if (lpEvent->state == 0xf0) {
514+ lpEvent->lpData[0] = 0xf0; // 可変長データの先頭は0xF0
515+ dw--;
516+ memcpy(lpEvent->lpData + 1, pData, dw);
517+ } else {
518+ memcpy(lpEvent->lpData, pData, dw);
519+ }
520+ pData += dw;
521+ nSize -= dw;
522+ } else if (lpEvent->state == 0xff) {
523+ // メタイベント
524+ lpEvent->type = *pData++; // typeの取得
525+ nSize--;
526+ if ((pData = ReadDelta(pData, dw, nSize)) == NULL) {
527+ // データ不正
528+ return false;
529+ }
530+
531+ lpEvent->nData = dw;
532+ if (dw != 0) {
533+ lpEvent->lpData = new unsigned char[dw];
534+ memcpy(lpEvent->lpData, pData, dw);
535+ pData += dw;
536+ nSize -= dw;
537+ }
538+
539+ if (lpEvent->type == 0x2f) {
540+ // トラックの終端
541+ *ppData = pData;
542+ return true;
543+ }
544+ }
545+ break;
546+
547+ default:
548+ // ステータス不正
549+ return false;
550+ }
551+ statePrev = lpEvent->state;
552+
553+ lpEvent->lpNext = new CMidiEvent();
554+ lpEvent = lpEvent->lpNext;
555+ if (lpEvent == NULL) {
556+ // メモリ不足
557+ return false;
558+ }
559+ }
560+
561+ return false;
562+}
563+
564+
565+//! デルタタイムの取得
566+unsigned char* CMidi::ReadDelta(unsigned char* pData, unsigned long& nDelta, unsigned int& nSize)
567+{
568+ nDelta = 0;
569+ for (int i = 0; i < sizeof(unsigned long); i++) {
570+ unsigned char nTmp = *pData++;
571+ if (nSize-- == 0) {
572+ return NULL;
573+ }
574+ nDelta = (nDelta << 7) | (nTmp & 0x7f);
575+ if ((nTmp & 0x80) == 0) {
576+ break; // MSBが立っていないならば、次のバイトはデルタタイムではないので抜ける
577+ }
578+ }
579+
580+ return pData;
581+}
582+
583+
584+//! トラックデータのマージ
585+CMidiEvent* CMidi::Marge(CMidiEvent** lplpEvent, unsigned short nTrack)
586+{
587+ unsigned long dwPrevAbsolute = 0; // 一つ前の絶対時間
588+ CMidiEvent* lpEvent = new CMidiEvent(); // 現在のイベント
589+ unsigned long* lpdwTotal = new unsigned long[nTrack]; // 各トラックの絶対時間
590+ CMidiEvent** pEventBase = new CMidiEvent*[nTrack];
591+
592+ if (lpEvent == NULL || lpdwTotal == NULL || pEventBase == NULL) {
593+ // メモリ不足
594+ delete lpEvent;
595+ delete[] lpdwTotal;
596+ delete[] pEventBase;
597+ return NULL;
598+ }
599+
600+ memcpy(pEventBase, lplpEvent, sizeof(CMidiEvent*) * nTrack);
601+ memset(lpdwTotal, 0, sizeof(unsigned long) * nTrack);
602+ CMidiEvent* lpHead = lpEvent;
603+ while (1) {
604+ int nIndex = -1; // トラックのインデックス
605+ unsigned long dwAbsolute = (unsigned long)-1; // 絶対時間(0xFFFFFFFF)
606+
607+ // 最も絶対時間が低いイベントを見つける
608+ for (int i = 0; i < nTrack; i++) {
609+ if (pEventBase[i]->lpNext == NULL) {
610+ continue; // トラックの終端まで走査した
611+ }
612+
613+ if ((lpdwTotal[i] + pEventBase[i]->dwDelta) < dwAbsolute) {
614+ nIndex = i;
615+ dwAbsolute = lpdwTotal[i] + pEventBase[i]->dwDelta;
616+ }
617+ }
618+
619+ if (nIndex == -1) {
620+ // 全てのトラックを走査したのでTrackOfEndを付加する
621+ lpEvent->state = 0xff;
622+ lpEvent->data1 = 0x2f;
623+ lpEvent->data2 = 0x00;
624+ lpEvent->dwDelta = 0;
625+ break;
626+ }
627+
628+ if (pEventBase[nIndex]->state != 0xff || pEventBase[nIndex]->data1 != 0x2f) { // TrackOfEndははじく
629+ lpEvent->state = pEventBase[nIndex]->state;
630+ lpEvent->data1 = pEventBase[nIndex]->data1;
631+ lpEvent->data2 = pEventBase[nIndex]->data2;
632+ lpEvent->type = pEventBase[nIndex]->type;
633+ lpEvent->nData = pEventBase[nIndex]->nData;
634+ lpEvent->dwDelta = dwAbsolute - dwPrevAbsolute;
635+ if (lpEvent->nData != 0) {
636+ lpEvent->lpData = new unsigned char[lpEvent->nData];
637+ if (lpEvent->lpData == NULL) {
638+ // メモリ不足
639+ ReleaseMain(lpHead);
640+ for (int j = 0; j < nTrack; j++) {
641+ ReleaseMain(pEventBase[j]);
642+ }
643+ delete[] lpdwTotal;
644+ delete[] pEventBase;
645+ return NULL;
646+ }
647+ memcpy(lpEvent->lpData, pEventBase[nIndex]->lpData, lpEvent->nData);
648+ }
649+ lpEvent->lpNext = new CMidiEvent();
650+ lpEvent = lpEvent->lpNext;
651+ if (lpEvent == NULL) {
652+ // メモリ不足
653+ ReleaseMain(lpHead);
654+ for (int j = 0; j < nTrack; j++) {
655+ ReleaseMain(pEventBase[j]);
656+ }
657+ delete[] lpdwTotal;
658+ delete[] pEventBase;
659+ return NULL;
660+ }
661+ }
662+ dwPrevAbsolute = dwAbsolute;
663+ lpdwTotal[nIndex] += pEventBase[nIndex]->dwDelta; // 各トラックの絶対時間を更新
664+ pEventBase[nIndex] = pEventBase[nIndex]->lpNext;
665+ }
666+ for (int j = 0; j < nTrack; j++) {
667+ ReleaseMain(lplpEvent[j]);
668+ }
669+ delete[] pEventBase;
670+ delete[] lpdwTotal;
671+
672+ return lpHead;
673+}
674+
675+
676+//! 総時間の計算
677+unsigned long CMidi::CalcTotalTime(void) const
678+{
679+ if (m_pHeader == NULL) {
680+ return 0;
681+ }
682+ unsigned long nTotalTime = 0;
683+ unsigned long nTempo = 500000;
684+ unsigned long nRest = 0;
685+ unsigned long nTime = m_nTime;
686+ CMidiEvent* pData = m_pHeader;
687+ while (pData != NULL) {
688+ unsigned long nDelta = pData->dwDelta;
689+ if (pData->state == 0xff && pData->type == 0x51) {
690+ // セットテンポ
691+ nTempo = (unsigned long)(pData->lpData[2] | ((unsigned long)pData->lpData[1] << 8) | ((unsigned long)pData->lpData[0] << 16));
692+ }
693+ if (nDelta != 0 ) {
694+ unsigned long nTmp = (nDelta * nTempo) + nRest;
695+ unsigned long nMtime = nTmp / nTime;
696+ nRest = nTmp % nTime;
697+ nTotalTime += nMtime;
698+ }
699+ pData = pData->lpNext;
700+ }
701+
702+ return nTotalTime;
703+}
704+
705+
706+//! コールバック関数
707+void CALLBACK CMidi::TimeCallbackProc(unsigned int nID, unsigned int nMsg, unsigned long nUser, unsigned long nReserve1, unsigned long nReserve2)
708+{
709+ CMidi* pClass = (CMidi*)nUser;
710+
711+ if (pClass == NULL || pClass->m_pNowPoint == NULL) return;
712+
713+ unsigned long nTime = timeGetTime();
714+ if (pClass->m_nAttr_Pause != 0) {
715+ // ポーズ中
716+ pClass->m_nPrevTime = nTime;
717+ return;
718+ }
719+
720+ // ボリューム設定
721+ if (pClass->m_nAttr_UpdateV != 0) {
722+ for (int i = 0; i < 16; i++) {
723+ unsigned long nVol;
724+ if ((pClass->m_nMuteFlag & (1<<i)) == 0) {
725+ nVol = ((pClass->m_nMasterVolume * pClass->m_nVolume[i]) << 8) & 0x7f0000;
726+ } else {
727+ nVol = 0;
728+ }
729+ midiOutShortMsg(pClass->m_hMidiOut, nVol | (0x07 << 8) | (0xb0 + i));
730+ }
731+ pClass->m_nAttr_UpdateV = 0;
732+ }
733+ // パンポット設定
734+ if (pClass->m_nAttr_UpdateP != 0) {
735+ for (int i = 0; i < 16; i++) {
736+ long nPan = (long)pClass->m_nPanpot[i] + ((pClass->m_nMasterPanpot * 2) - 128);
737+ nPan = (nPan < 0)? 0 : ((nPan > 127)? 127 : nPan);
738+ midiOutShortMsg(pClass->m_hMidiOut, (nPan << 16) | (0x0a << 8) | (0xb0 + i));
739+ }
740+ pClass->m_nAttr_UpdateP = 0;
741+ }
742+
743+ unsigned long nTmp = (((nTime - pClass->m_nPrevTime) * pClass->m_nTimeBias) + pClass->m_nNowTimeRest);
744+ pClass->m_nNowTimeRest = (nTmp % 1000);
745+ pClass->m_nNowTime += nTmp / 1000;
746+ pClass->m_nPrevTime = nTime;
747+ while (1) {
748+ if (pClass->m_nNextTime > pClass->m_nNowTime) break;
749+ if (pClass->m_pNowPoint->state == 0xff) {
750+ // メタイベント
751+ if (pClass->m_pNowPoint->type == 0x51) {
752+ // セットテンポ
753+ pClass->m_nTempo = (unsigned long)(pClass->m_pNowPoint->lpData[2] | ((unsigned long)pClass->m_pNowPoint->lpData[1] << 8) | ((unsigned long)pClass->m_pNowPoint->lpData[0] << 16));
754+ }
755+ } else if (pClass->m_pNowPoint->state == 0xf0) {
756+ // SysExイベント
757+ MIDIHDR mh = {0};
758+
759+ mh.lpData = (LPSTR)pClass->m_pNowPoint->lpData;
760+ mh.dwFlags = 0;
761+ mh.dwBufferLength = pClass->m_pNowPoint->nData;
762+ mh.dwBytesRecorded = pClass->m_pNowPoint->nData;
763+
764+ midiOutPrepareHeader(pClass->m_hMidiOut, &mh, sizeof(MIDIHDR));
765+ midiOutLongMsg(pClass->m_hMidiOut, &mh, sizeof(MIDIHDR));
766+ while ((mh.dwFlags & MHDR_DONE) == 0);
767+ midiOutUnprepareHeader(pClass->m_hMidiOut, &mh, sizeof(MIDIHDR));
768+ } else {
769+ // MIDIイベント
770+ unsigned char nStatus = pClass->m_pNowPoint->state;
771+ unsigned long nData2 = pClass->m_pNowPoint->data2;
772+ if ((nStatus & 0xf0) == 0xb0) {
773+ int nCh = (nStatus & 0x0f);
774+ if (pClass->m_pNowPoint->data1 == 0x07) {
775+ // ボリューム
776+ pClass->m_nVolume[nCh] = (unsigned short)nData2;
777+ if ((pClass->m_nMuteFlag & (1<<nCh)) != 0) {
778+ // ミュート
779+ nData2 = 0;
780+ } else {
781+ // ベロシティ計算
782+ nData2 *= pClass->m_nMasterVolume;
783+ nData2 >>= 8;
784+ }
785+ } else if (pClass->m_pNowPoint->data1 == 0x0a) {
786+ // パンポット
787+ pClass->m_nPanpot[nCh] = (unsigned char)nData2;
788+ long nPan = (long)nData2 + ((pClass->m_nMasterPanpot * 2) - 128);
789+ nPan = (nPan < 0)? 0 : ((nPan > 127)? 127 : nPan);
790+ nData2 = (unsigned long)nPan;
791+ }
792+ }
793+ unsigned long dwMsg = (unsigned long)(nStatus | ((unsigned long)pClass->m_pNowPoint->data1 << 8) | (nData2 << 16));
794+ midiOutShortMsg(pClass->m_hMidiOut, dwMsg);
795+ }
796+ pClass->m_pNowPoint = pClass->m_pNowPoint->lpNext;
797+ if (pClass->m_pNowPoint != NULL) {
798+ unsigned long nTmp = (pClass->m_pNowPoint->dwDelta * pClass->m_nTempo) + pClass->m_nTimeRest;
799+ unsigned long nMtime = nTmp / pClass->m_nTime;
800+ pClass->m_nTimeRest = nTmp % pClass->m_nTime;
801+ if (nMtime != 0) {
802+ pClass->m_nNextTime += nMtime;
803+ }
804+ } else {
805+ // データ終了
806+ if ((pClass->m_nLoop + 1) > 1) {
807+ pClass->m_nLoop--;
808+ }
809+ if (pClass->m_nLoop == 0) {
810+ timeKillEvent(pClass->m_nTimerID);
811+ pClass->m_nTimerID = 0;
812+ break;
813+ } else {
814+ pClass->m_nNextTime = 0;
815+ pClass->m_nNowTime = 0;
816+ pClass->m_nNowTimeRest = 0;
817+ pClass->m_nTimeRest = 0;
818+ pClass->m_pNowPoint = pClass->m_pHeader;
819+ }
820+ }
821+ }
822+}
823+
824+
825+void CMidi::ThreadMain()
826+{
827+ while (true) {
828+ // イベント待ち
829+ unsigned long Result = ::WaitForSingleObject(m_hEvent, INFINITE);
830+
831+ if (m_bEnd == true) return;
832+
833+ while (true) {
834+ // クリティカルセクションに入る
835+ ::EnterCriticalSection(&m_stCriticalSection);
836+
837+ if (m_stQue[0].bUse == false) {
838+ // クリティカルセクションから抜けてループからも抜ける
839+ ::LeaveCriticalSection(&m_stCriticalSection);
840+ break;
841+ }
842+
843+ EVENT_QUE Que;
844+ EVENT_QUE* pQue = &Que;
845+ ::CopyMemory(pQue, &m_stQue[0], sizeof(EVENT_QUE));
846+
847+ // キューを詰める
848+ ::MoveMemory(&m_stQue[0], &m_stQue[1], sizeof(EVENT_QUE) * (EVT_MAX - 1));
849+ m_stQue[EVT_MAX - 1].bUse = false;
850+
851+ // クリティカルセクションから抜ける
852+ ::LeaveCriticalSection(&m_stCriticalSection);
853+ // イベント処理
854+ switch (pQue->EventType) {
855+ case EVT_LOAD:
856+ if ( pQue->Data_Load.nType == 0 ) {
857+ _AttachMidiData((unsigned char*)pQue->Data_Load.pData, pQue->Data_Load.nSize);
858+ } else if ( pQue->Data_Load.nType == 1 ) {
859+ _AttachMidiFile(pQue->Data_Load.pData, pQue->Data_Load.nStart, pQue->Data_Load.nSize);
860+ }
861+ delete[] pQue->Data_Load.pData;
862+ break;
863+ case EVT_PLAY:
864+ _Play(pQue->Data_Play.nLoopCount);
865+ break;
866+ case EVT_STOP:
867+ _Stop();
868+ break;
869+ case EVT_PAUSE:
870+ _Pause();
871+ break;
872+ case EVT_RELEASE:
873+ return;
874+ }
875+ }
876+ }
877+}
878+
879+
880+//! スレッド処理
881+unsigned long CALLBACK CMidi::ThreadProc(void* pParameter)
882+{
883+ CMidi* pMidi = (CMidi*)pParameter;
884+
885+ // メイン関数呼び出し
886+ pMidi->ThreadMain();
887+ pMidi->_Release();
888+
889+ // メモリから解放
890+ delete pMidi;
891+
892+ // スレッド終了
893+ ExitThread(0);
894+}
895+
896+
897+/* Bottom of midi.h */
Show on old repository browser