Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
716 lvd 1
#include "std.h"
2
 
3
#include "emul.h"
4
#include "vars.h"
5
#include "vs1001.h"
6
#include "bass.h"
7
#include "snd_bass.h"
8
 
9
bool SkipZeroes = true;
10
 
11
void TRingBuffer::Reset()
12
{
13
    CritSect.Lock();
14
    WrPos = RdPos = 0;
15
    Dreq = true;
16
    Count = 0;
17
    Cancelled = false;
18
    NotEmpty.Reset();
19
    CritSect.Unlock();
20
}
21
 
22
void TRingBuffer::Put(u8 Val)
23
{
24
    CritSect.Lock();
25
    Buf[WrPos++] = Val;
26
    WrPos &= (Size - 1);
27
    Count++;
28
    assert(Count < Size);
29
    Dreq = (Size - Count) > 32;
30
    NotEmpty.Set();
31
    CritSect.Unlock();
32
}
33
 
34
u32 TRingBuffer::Get(void *Data, u32 ReqLen)
35
{
36
    u32 RetLen;
37
    u8 *Ptr = (u8 *)Data;
38
 
39
retry:
40
    NotEmpty.Wait();
41
 
42
    CritSect.Lock();
43
    if(Count == 0)
44
    {
45
        CritSect.Unlock();
46
        if(Cancelled)
47
            return 0;
48
        goto retry;
49
    }
50
 
51
    assert(Count != 0);
52
 
53
    if(Cancelled)
54
    {
55
        CritSect.Unlock();
56
        return 0;
57
    }
58
 
59
    RetLen = min(Count, ReqLen);
60
    if(RetLen)
61
    {
62
        u32 RdLen = min(RetLen, Size - RdPos);
63
        memcpy(Ptr, &Buf[RdPos], RdLen);
64
        RdPos += RdLen;
65
        RdPos &= (Size - 1);
66
        Ptr += RdLen;
67
        if(RetLen > RdLen)
68
        {
69
            assert(RdPos == 0);
70
            RdLen = RetLen - RdLen;
71
            memcpy(Ptr, Buf, RdLen);
72
            RdPos += RdLen;
73
            RdPos &= (Size - 1);
74
        }
75
        Count -= RetLen;
76
 
77
        Dreq = (Size - Count) > 32;
78
 
79
        if(Count == 0)
80
            NotEmpty.Reset();
81
    }
82
    CritSect.Unlock();
83
 
84
    return RetLen;
85
}
86
 
87
BASS_FILEPROCS TVs1001::Procs = { TVs1001::StreamClose, TVs1001::StreamLen, TVs1001::StreamRead, TVs1001::StreamSeek };
88
 
89
TVs1001::TVs1001() : EventStreamClose(FALSE)
90
{
91
    Mp3Stream = 0;
92
    ThreadHandle = 0;
93
 
94
    Regs[VOL] = 0; // max volume on all channels
95
 
96
    Reset();
97
 
98
    SetVol(Regs[VOL]);
99
}
100
 
101
void TVs1001::Reset()
102
{
103
//    printf(__FUNCTION__"\n");
104
 
105
    memset(Regs, 0, sizeof(Regs));
106
 
107
    CurState = ST_IDLE;
108
    Idx = 0;
109
    Msb = Lsb = 0xFF;
110
    nCs = true;
111
    RingBuffer.Reset();
112
 
113
    if(conf.gs_type != 1)
114
        return;
115
 
116
    static bool BassInit = false;
117
    if(!BassInit)
118
    {
119
        BASS::Init(-1, conf.sound.fq, BASS_DEVICE_LATENCY, wnd, NULL);
120
        ThreadHandle = (HANDLE)_beginthreadex(0, 0, Thread, this, 0, 0);
121
        BassInit = true;
122
    }
123
}
124
 
125
void TVs1001::SetNcs(bool nCs)
126
{
127
    TVs1001::nCs = nCs;
128
    if(nCs)
129
        CurState = ST_IDLE;
130
}
131
 
132
u8 TVs1001::Rd()
133
{
134
    if(nCs) // codec not selected
135
        return 0xFF;
136
 
137
    u16 Val = Rd(Idx);
138
    u8 RetVal = 0xFF;
139
    TState NextState = CurState;
140
    switch(CurState)
141
    {
142
    case ST_RD_MSB: RetVal = (Val >> 8U) & 0xFF; NextState = ST_RD_LSB; break;
143
    case ST_RD_LSB: RetVal = Val & 0xFF;  NextState = ST_IDLE; break;
144
    }
145
//    printf("Vs1001: RD %s->%s, val = 0x%X\n", State2Str(CurState), State2Str(NextState), RetVal);
146
    CurState = NextState;
147
 
148
    return RetVal;
149
}
150
 
151
u16 TVs1001::Rd(int Idx)
152
{
153
    switch(Idx)
154
    {
155
    case MODE:
156
    case CLOCKF:
157
    case STATUS:
158
    case AUDATA:
159
    case HDAT0:
160
    case HDAT1:
161
    case AIADDR:
162
    case VOL:
163
    case AICTRL0:
164
    case AICTRL1:
165
        return Regs[Idx];
166
    case DECODE_TIME:
167
        return GetDecodeTime();
168
    }
169
    return 0xFFFF;
170
}
171
 
172
void TVs1001::Wr(int Idx, u16 Val)
173
{
174
    switch(Idx)
175
    {
176
    case CLOCKF:
177
    case WRAM_W:
178
    case WRAMADDR_W:
179
    case AIADDR:
180
    case AICTRL0:
181
    case AICTRL1:
182
        Regs[Idx] = Val;
183
    break;
184
 
185
    case VOL:
186
        Regs[Idx] = Val;
187
        SetVol(Val);
188
    break;
189
 
190
    case MODE:
191
        Regs[Idx] = Val;
192
        if(Val & SM_RESET)
193
            SoftReset();
194
    break;
195
 
196
    case STATUS:
197
        Regs[Idx] = Val & 0xF; // vs1001
198
    break;
199
    }
200
}
201
 
202
void TVs1001::WrCmd(u8 Val)
203
{
204
    TState NextState = ST_IDLE;
205
 
206
    if(nCs) // codec not selected
207
        return;
208
 
209
    switch(CurState)
210
    {
211
    case ST_IDLE:
212
        switch(Val)
213
        {
214
        case CMD_RD: NextState = ST_RD_IDX; break;
215
        case CMD_WR: NextState = ST_WR_IDX; break;
216
        default:
217
//            printf("Vs1001: invalid cmd = 0x%X\n", Val);
218
           ;
219
        }
220
    break;
221
    case ST_RD_IDX: Idx = Val; NextState = ST_RD_MSB; break;
222
    case ST_WR_IDX: Idx = Val; NextState = ST_WR_MSB; break;
223
    case ST_WR_MSB: Msb = Val; NextState = ST_WR_LSB; break;
224
    case ST_WR_LSB:
225
        Lsb = Val;
226
        Wr(Idx, (Msb << 8U) | Lsb);
227
    break;
228
 
229
    case ST_RD_MSB:
230
    case ST_RD_LSB:
231
        NextState = CurState;
232
    break;
233
 
234
    default:
235
//        printf("Vs1001: WR invalid state = %s\n", State2Str(CurState));
236
        ;
237
    }
238
//    printf("Vs1001: WR %s->%s, val = 0x%X\n", State2Str(CurState), State2Str(NextState), Val);
239
    CurState = NextState;
240
}
241
 
242
void TVs1001::Wr(u8 Val)
243
{
244
//    printf(__FUNCTION__" val = 0x%X\n", Val);
245
    if(!Mp3Stream && SkipZeroes)
246
    {
247
        if(Val == 0) // skip zeroes before format detection
248
            return;
249
        SkipZeroes = false;
250
    }
251
 
252
    RingBuffer.Put(Val);
253
}
254
 
255
void TVs1001::SetVol(u16 Vol)
256
{
257
//   __debugbreak();
258
   if(!Mp3Stream)
259
       return;
260
 
261
   float VolDbR = (Vol & 0xFF) / 2.0f;
262
   float VolDbL = ((Vol >> 8U) & 0xFF) / 2.0f;
263
   float VolR = powf(10.0f, -VolDbR / 10.0f);
264
   float VolL = powf(10.0f, -VolDbL / 10.0f);
265
   float Pan = VolR - VolL;
266
   float VolM = (VolR + VolL) / 2.0f;
267
 
268
//   printf("%s, Vol = %u\n", __FUNCTION__, Vol);
269
   if (!BASS::ChannelSetAttribute(Mp3Stream, BASS_ATTRIB_VOL, VolM))
270
       printf("BASS_ChannelSetAttribute() [vol]\n");
271
   if (!BASS::ChannelSetAttribute(Mp3Stream, BASS_ATTRIB_PAN, Pan))
272
       printf("BASS_ChannelSetAttribute() [pan]\n");
273
}
274
 
275
u16 TVs1001::GetDecodeTime()
276
{
277
    if(!Mp3Stream)
278
        return 0;
279
 
280
    QWORD Pos = BASS::ChannelGetPosition(Mp3Stream, BASS_POS_BYTE);
281
    double Time = BASS::ChannelBytes2Seconds(Mp3Stream, Pos);
282
    return (u16)Time;
283
}
284
 
285
// called from main loop when processing ngs z80 code
286
void TVs1001::SoftReset()
287
{
288
//    printf("%s\n", __FUNCTION__);
289
 
290
    ShutDown();
291
 
292
    if(Mp3Stream)
293
    {
294
        if(!BASS::ChannelStop(Mp3Stream))
295
        {
296
            printf("BASS_ChannelStop()\n");
297
            assert(false);
298
        }
299
 
300
        if(!BASS::StreamFree(Mp3Stream))
301
        {
302
            printf("BASS_ChannelStop()\n");
303
            assert(false);
304
        }
305
 
306
        EventStreamClose.Wait();
307
        EventStreamClose.Reset();
308
        Mp3Stream = 0;
309
    }
310
 
311
    RingBuffer.Reset();
312
    SkipZeroes = true;
313
    ThreadHandle = (HANDLE)_beginthreadex(0, 0, Thread, this, 0, 0);
314
}
315
 
316
void TVs1001::ShutDown()
317
{
318
    RingBuffer.Cancel();
319
 
320
    if(ThreadHandle)
321
    {
322
        WaitForSingleObject(ThreadHandle, INFINITE);
323
        CloseHandle(ThreadHandle);
324
        ThreadHandle = 0;
325
    }
326
}
327
 
328
// called from main loop priodicaly
329
void TVs1001::Play()
330
{
331
   if(!Mp3Stream)
332
       return;
333
 
334
   BASS::ChannelPlay(Mp3Stream, FALSE);
335
}
336
 
337
// stream file format detection tread
338
void TVs1001::Thread()
339
{
340
//    printf(__FUNCTION__"\n");
341
    Mp3Stream = BASS::StreamCreateFileUser(STREAMFILE_BUFFER, BASS_SAMPLE_FLOAT | BASS_STREAM_BLOCK, &Procs, this);
342
    if(!Mp3Stream)
343
    {
344
//        printf(__FUNCTION__" Err = %d\n", BASS_ErrorGetCode());
345
    }
346
//    printf(__FUNCTION__"->Exit\n");
347
}
348
 
349
// bass asynchronous callback
350
void TVs1001::StreamClose()
351
{
352
    EventStreamClose.Set();
353
}
354
 
355
// bass asynchronous callback
356
QWORD TVs1001::StreamLen()
357
{
358
    return 0;
359
}
360
 
361
// bass asynchronous callback
362
DWORD TVs1001::StreamRead(void *Buffer, DWORD Length)
363
{
364
    DWORD Len = RingBuffer.Get(Buffer, Length);
365
//    printf(__FUNCTION__"->%d/%d\n", Length, Len);
366
 
367
/*
368
    static FILE *f = fopen("dump.mp3", "wb");
369
    if(Len != 0)
370
        fwrite(Buffer, Len, 1, f);
371
*/
372
    return Len;
373
}
374
 
375
// bass asynchronous callback
376
BOOL TVs1001::StreamSeek(QWORD offset)
377
{
378
    return FALSE;
379
}
380
 
381
#define STATE2STR(x) case x:  return #x
382
 
383
const char *TVs1001::State2Str(TState State)
384
{
385
    switch(State)
386
    {
387
    STATE2STR(ST_IDLE);
388
    STATE2STR(ST_RD);
389
    STATE2STR(ST_WR);
390
    STATE2STR(ST_RD_IDX);
391
    STATE2STR(ST_WR_IDX);
392
    STATE2STR(ST_RD_MSB);
393
    STATE2STR(ST_RD_LSB);
394
    STATE2STR(ST_WR_MSB);
395
    STATE2STR(ST_WR_LSB);
396
    }
397
    return "???";
398
}
399
 
400
TVs1001 Vs1001;