1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
|
#ifndef NW4R_SND_SEQ_PLAYER_H
#define NW4R_SND_SEQ_PLAYER_H
/*******************************************************************************
* headers
*/
#include "common.h"
#include "nw4r/snd/snd_BasicPlayer.h"
#include "nw4r/snd/snd_DisposeCallbackManager.h" // DisposeCallback
#include "nw4r/snd/snd_SeqTrack.h"
#include "nw4r/snd/snd_SoundThread.h"
#include "nw4r/ut/ut_Lock.h"
/*******************************************************************************
* types
*/
// forward declarations
namespace nw4r { namespace snd { namespace detail { class Channel; }}}
namespace nw4r { namespace snd { namespace detail { class NoteOnCallback; }}}
namespace nw4r { namespace snd { namespace detail { struct NoteOnInfo; }}}
namespace nw4r { namespace snd { namespace detail { class SeqTrack; }}}
namespace nw4r { namespace snd { namespace detail { class SeqTrackAllocator; }}}
namespace nw4r { namespace snd
{
// [R89JEL]:/bin/RVL/Debug/mainD.elf:.debug::0x2dbb2
struct SeqUserprocCallbackParam
{
s16 volatile *localVariable; // size 0x04, offset 0x00
s16 volatile *globalVariable; // size 0x04, offset 0x04
s16 volatile *trackVariable; // size 0x04, offset 0x08
bool cmpFlag; // size 0x01, offset 0x0C
/* 3 bytes padding */
}; // size 0x10
}} // namespace nw4r::snd
/*******************************************************************************
* classes
*/
namespace nw4r { namespace snd { namespace detail
{
// [R89JEL]:/bin/RVL/Debug/mainD.elf:.debug::0x2dfad
class SeqPlayer : public BasicPlayer,
public DisposeCallback,
public SoundThread::PlayerCallback
{
// enums
public:
// [R89JEL]:/bin/RVL/Debug/mainD.elf:.debug::0x2dee8
enum OffsetType
{
OFFSET_TYPE_TICK,
OFFSET_TYPE_MILLISEC,
};
// [R89JEL]:/bin/RVL/Debug/mainD.elf:.debug::0x2df3b
enum SetupResult
{
SETUP_SUCCESS,
SETUP_ERR_CANNOT_ALLOCATE_TRACK,
SETUP_ERR_UNKNOWN
};
// nested types
public:
// [R89JEL]:/bin/RVL/Debug/mainD.elf:.debug::0x2cce4
struct ParserPlayerParam
{
u8 volume; // size 0x01, offset 0x00
u8 priority; // size 0x01, offset 0x01
u8 timebase; // size 0x01, offset 0x02
/* 1 byte padding */
u16 tempo; // size 0x02, offset 0x04
/* 2 bytes padding */
NoteOnCallback *callback; // size 0x04, offset 0x08
}; // size 0x0c
// typedefs
public:
typedef void SeqUserprocCallback(u16 procId,
SeqUserprocCallbackParam *param,
void *callbackData);
// methods
public:
// cdtors
SeqPlayer();
virtual ~SeqPlayer();
// virtual function ordering
// vtable BasicPlayer
virtual bool Start();
virtual void Stop();
virtual void Pause(bool flag);
virtual bool IsActive() const { return mActiveFlag; }
virtual bool IsStarted() const { return mStartedFlag; }
virtual bool IsPause() const { return mPauseFlag; }
// vtable DisposeCallback
virtual void InvalidateData(void const *start, void const *end);
virtual void InvalidateWaveData(void const *, void const *) {}
// vtable SeqPlayer
/* WARNING: must come before SoundThread::PlayerCallback virtual
* functions
*/
virtual void ChannelCallback(Channel *channel ATTR_UNUSED) {}
// vtable SoundThread::PlayerCallback
virtual void OnUpdateFrameSoundThread() { Update(); }
virtual void OnShutdownSoundThread() { Stop(); }
// methods
SetupResult Setup(SeqTrackAllocator *trackAllocator, u32 allocTracks,
int voiceOutCount, NoteOnCallback *callback);
void Update();
void Skip(OffsetType offsetType, int offset);
void Shutdown();
bool IsReleasePriorityFix() const { return mReleasePriorityFixFlag; }
f32 GetPanRange() const { return mPanRange; }
int GetVoiceOutCount() const { return mVoiceOutCount; }
ParserPlayerParam &GetParserPlayerParam() { return mParserParam; }
SeqTrack *GetPlayerTrack(int trackNo);
s16 volatile *GetVariablePtr(int varNo);
s16 GetLocalVariable(int varNo) const;
void SetLocalVariable(int varNo, s16 value);
static void SetGlobalVariable(int varNo, s16 value);
void SetTempoRatio(f32 tempo);
void SetReleasePriorityFix(bool fix);
void SetChannelPriority(int priority);
void SetSeqUserprocCallback(SeqUserprocCallback *callback, void *arg);
void SetPlayerTrack(int trackNo, SeqTrack *track);
f32 CalcTickPerMsec() const
{
return CalcTickPerMinute() / (60 * 1000);
}
f32 CalcTickPerMinute() const
{
return mParserParam.timebase * mParserParam.tempo * mTempoRatio;
}
u32 GetTickCounter() const {
return mTickCounter;
}
void SetSeqData(void const *seqBase, s32 seqOffset);
void CallSeqUserprocCallback(u16 procId, SeqTrack *track);
Channel *NoteOn(int bankNo, NoteOnInfo const ¬eOnInfo);
void SetTrackMute(u32 trackFlags, SeqMute mute);
void SetTrackSilence(u32 trackFlags, bool silence, int fadeFrames);
void SetTrackVolume(u32 trackFlags, f32 volume);
static void InitSeqPlayer();
private:
void InitParam(int voiceOutCount, NoteOnCallback *callback);
void UpdateChannelParam();
void CloseTrack(int trackNo);
void FinishPlayer();
int ParseNextTick(bool doNoteOn); // meant to be bool?
void UpdateTick(int msec);
void SkipTick();
template <typename T>
void SetTrackParam(u32 trackFlags, void (SeqTrack::*pSetter)(T), T param) {
ut::AutoInterruptLock lock;
for (int i = 0; i < TRACK_NUM && trackFlags != 0;
trackFlags >>= 1, i++) {
if (trackFlags & 1) {
SeqTrack* pTrack = GetPlayerTrack(i);
if (pTrack != NULL) {
(pTrack->*pSetter)(param);
}
}
}
}
template <typename T, typename U>
void SetTrackParam(u32 trackFlags, void (SeqTrack::*pSetter)(T, U), T param, U param2) {
ut::AutoInterruptLock lock;
for (int i = 0; i < TRACK_NUM && trackFlags != 0;
trackFlags >>= 1, i++) {
if (trackFlags & 1) {
SeqTrack* pTrack = GetPlayerTrack(i);
if (pTrack != NULL) {
(pTrack->*pSetter)(param, param2);
}
}
}
}
// static members
public:
static int const MAX_SKIP_TICK_PER_FRAME = 768;
static int const DEFAULT_TEMPO = 120;
static int const DEFAULT_TIMEBASE = 48;
static int const VARIABLE_DEFAULT_VALUE = -1;
static int const TRACK_NUM_PER_PLAYER = 16;
static int const GLOBAL_VARIABLE_NUM = 16;
static int const PLAYER_VARIABLE_NUM = 16;
static const int TRACK_NUM = 16;
private:
static s16 mGlobalVariable[GLOBAL_VARIABLE_NUM];
// members
private:
/* base BasicPlayer */ // size 0x0a4, offset 0x000
/* base DisposeCallback */ // size 0x00c, offset 0x0a4
/* base SoundThread::PlayerCallback */ // size 0x00c, offset 0x0b0
bool mActiveFlag; // size 0x001, offset 0x0ec
bool mStartedFlag; // size 0x001, offset 0x0ed
bool mPauseFlag; // size 0x001, offset 0x0ee
bool mReleasePriorityFixFlag; // size 0x001, offset 0x0ef
f32 mPanRange; // size 0x004, offset 0x0f0
f32 mTempoRatio; // size 0x004, offset 0x0f4
f32 mTickFraction; // size 0x004, offset 0x0f8
u32 mSkipTickCounter; // size 0x004, offset 0x0fc
f32 mSkipTimeCounter; // size 0x004, offset 0x100
s32 mVoiceOutCount; // size 0x004, offset 0x104
ParserPlayerParam mParserParam; // size 0x00c, offset 0x108
SeqTrackAllocator *mSeqTrackAllocator; // size 0x004, offset 0x114
SeqUserprocCallback *mSeqUserprocCallback; // size 0x004, offset 0x118
void *mSeqUserprocCallbackArg; // size 0x004, offset 0x11c
SeqTrack *mTracks[TRACK_NUM_PER_PLAYER]; // size 0x040, offset 0x120
s16 volatile mLocalVariable[PLAYER_VARIABLE_NUM]; // size 0x020, offset 0x160
u32 mTickCounter; // size 0x004, offset 0x180
}; // size 0x184
}}} // namespace nw4r::snd::detail
#endif // NW4R_SND_SEQ_PLAYER_H
|