PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
cdrom.c
Go to the documentation of this file.
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright 2005, ps2dev - http://www.ps2dev.org
7# Licenced under GNU Library General Public License version 2
8*/
9
15#include <stdio.h>
16#include <thbase.h>
17#include <thsemap.h>
18#include <loadcore.h>
19#include <sysmem.h>
20#include <intrman.h>
21#include <sifcmd.h>
22#include <libsd.h>
23#include <cdvdman.h>
24#include <sysclib.h>
25
26#include <audsrv.h>
27#include "cdrom.h"
28#include "common.h"
29#include "rpc_server.h"
30#include "rpc_client.h"
31#include "upsamplers.h"
32#include "spu.h"
33#include "hw.h"
34#include "debug_printf.h"
35
36/* cdda */
38static int cdda_initialized = 0;
40static int cd_playing = 0;
42static volatile int cd_paused = 0;
44static int cdda_play_tid = -1;
46static volatile int cdda_pos = 0;
48static int cdda_play_start = 0;
50static int cdda_play_end = 0;
54static unsigned char raw_toc[3000];
55
57static int cd_transfer_sema = -1;
58
60static u8 cd_ringbuf[SECTOR_SIZE*8] __attribute__((aligned (16)));
62static u8 cd_sparebuf[1880] __attribute__((aligned (16)));
63static u8 core0_buf[0x1000] __attribute__((aligned (16)));
64
65static short cd_rendered_left[512];
66static short cd_rendered_right[512];
67
68static int audsrv_cd_init()
69{
70 toc.num_tracks = 0;
71
72 if (cd_transfer_sema < 0)
73 {
74 cd_transfer_sema = CreateMutex(0);
75 if (cd_transfer_sema < 0)
76 {
77 return AUDSRV_ERR_OUT_OF_MEMORY;
78 }
79 }
80
81 return 0;
82}
83
91static int cd_transfer_complete(void *arg)
92{
93 (void)arg;
94
95 iSignalSema(cd_transfer_sema);
96 return 1;
97}
98
103{
104 int type = sceCdGetDiskType();
105
106 if (type == 0)
107 {
108 /* no disc inserted */
109 return -AUDSRV_ERR_NO_DISC;
110 }
111
112 return type;
113}
114
119{
120 return sceCdStatus();
121}
122
126static int process_toc()
127{
128 int track;
129
130 /* retrieve toc and parse it */
132 toc.num_tracks = btoi(raw_toc[17]);
133
134 //print_hex_buffer(raw_toc, sizeof(raw_toc));
135
136 for (track=0; track<toc.num_tracks; track++)
137 {
138 unsigned char *ptr;
139
140 ptr = raw_toc + 37 + (10*track);
141 toc.tracks[track].track = track;
142 toc.tracks[track].minute = btoi(ptr[0]);
143 toc.tracks[track].second = btoi(ptr[1]);
144 toc.tracks[track].sector = btoi(ptr[2]);
145 }
146
147 // FIXME: add extra track
148 toc.tracks[toc.num_tracks].track = toc.num_tracks;
149 toc.tracks[toc.num_tracks].minute = btoi(raw_toc[34]);
150 toc.tracks[toc.num_tracks].second = btoi(raw_toc[35]);
151 toc.tracks[toc.num_tracks].sector = btoi(raw_toc[36]);
152
153 DPRINTF("found %d tracks\n", toc.num_tracks);
154 return 0;
155}
156
157static int initialize_cdda()
158{
159 int err, dummy, type;
160
162 {
163 /* no need to reinitialize */
164 return 0;
165 }
166
167 printf("initializing cdda\n");
168
169 err = audsrv_cd_init();
170 if (err < 0)
171 {
172 return err;
173 }
174
175 /* initialize cdrom and set media = cd */
176 sceCdInit(0);
177
178 /* make sure disc is inserted, and check for cdda */
179 sceCdTrayReq(2, (u32 *)&dummy);
180 printf("TrayReq returned %d\n", dummy);
181
183 sceCdSync(0);
184
185 type = audsrv_get_cd_type();
186 DPRINTF("disc type: %d\n", type);
187
188 if (type != 0x11 && type != 0x13 && type != 0xfd)
189 {
190 /* not a cdda disc, or a ps1/ps2 with cdda tracks */
191 DPRINTF("not a cdda disc!\n");
192 return -AUDSRV_ERR_ARGS;
193 }
194
195 process_toc();
196
198 DPRINTF("cdda initialization completed successfully\n");
199 return 0;
200}
201
206{
207 int err = initialize_cdda();
208 if (err < 0)
209 {
210 return err;
211 }
212
213 return toc.num_tracks;
214}
215
221{
222 int err;
223 int offset;
224
225 err = initialize_cdda();
226 if (err < 0)
227 {
228 return err;
229 }
230
231 if (track < 1 || track > toc.num_tracks)
232 {
233 return -AUDSRV_ERR_ARGS;
234 }
235
236 offset = (toc.tracks[track].minute) * 60 + toc.tracks[track].second;
237 offset = (offset * 75) + toc.tracks[track].sector - 150;
238 return offset;
239}
240
247static int read_sectors(void *dest, int sector, int count)
248{
249 sceCdRMode mode;
250 int max_retries = 32;
251 int tries = 0;
252
253 mode.trycount = max_retries;
254 mode.spindlctrl = SCECdSpinNom;
255 mode.datapattern = SCECdSecS2048;
256 mode.pad = 0;
257
258 while (tries < max_retries)
259 {
260 /* wait until CD is ready to receive commands */
262
263 if (sceCdReadCDDA(sector, count, dest, &mode))
264 {
265 /* success! */
266 break;
267 }
268
269 tries++;
270 }
271
272 sceCdSync(0);
273
274 if (tries == max_retries)
275 {
276 return -1;
277 }
278
279 return count;
280}
281
284{
285 cd_playing = 0;
286 cdda_pos = 0;
287 cdda_play_start = 0;
288 cdda_play_end = 0;
289
290 /* disable streaming callbacks */
291 sceSdSetTransCallback(SD_CORE_0, NULL);
292 sceSdBlockTrans(SD_CORE_0, SD_TRANS_STOP, 0, 0, 0);
293}
294
299{
300 cd_paused = 1;
301 return AUDSRV_ERR_NOERROR;
302}
303
308{
309 cd_paused = 0;
310 return AUDSRV_ERR_NOERROR;
311}
312
316static void cdda_procedure(void *arg)
317{
318 int sz;
319 int nsectors;
320 int intr_state;
321 int offset, last_read;
322 upsample_t up;
323 upsampler_t up44k1;
324
325 (void)arg;
326
327 printf("cdda_procedure started with %d, %d\n", cdda_play_start, cdda_play_end);
328
330 {
331 /* nothing to play :| */
332 return;
333 }
334
335 /* audio discs are 44100hz, 16bit, stereo */
336 up44k1 = find_upsampler(44100, 16, 2);
337
339 printf("playing sectors %d - %d (%d sectors)\n", cdda_play_start, cdda_play_end, cdda_play_end - cdda_play_start);
340
341 /* fill entire buffer before starting to play */
342 offset = 0;
343 nsectors = sizeof(cd_ringbuf) / SECTOR_SIZE;
344 printf("filling buffer with nsectors %d..\n", nsectors);
345 if (read_sectors(cd_ringbuf, cdda_pos, nsectors) != nsectors)
346 {
347 printf("failed to read %d sectors..\n", nsectors);
348 return;
349 }
350
351 cdda_pos = cdda_pos + nsectors;
352
353 printf("sectors read.. now setting callbacks\n");
354
355 /* kick cd streaming */
356 sceSdSetTransCallback(SD_CORE_0, (void *)cd_transfer_complete);
357 sceSdBlockTrans(SD_CORE_0, SD_TRANS_LOOP, core0_buf, sizeof(core0_buf), 0);
358
359 printf("callbacks kicked, starting loop\n");
360 last_read = 0;
361
362 memset(cd_rendered_left, 0, sizeof(cd_rendered_left));
363 memset(cd_rendered_right, 0, sizeof(cd_rendered_right));
364
365 while (cdda_pos < cdda_play_end)
366 {
367 int block;
368 u8 *bufptr;
369
370 /* wait until it's safe to transmit */
371 WaitSema(cd_transfer_sema);
372
373 /* suspend all interrupts */
374 CpuSuspendIntr(&intr_state);
375
376 block = 1 - (sceSdBlockTransStatus(SD_CORE_0, 0) >> 24);
377 bufptr = core0_buf + (block << 11);
378
379 if (cd_paused == 0)
380 {
381 up.left = (short *)cd_rendered_left;
382 up.right = (short *)cd_rendered_right;
383
384 if ((unsigned int)(offset + 1880) < sizeof(cd_ringbuf))
385 {
386 /* enough bytes in ringbuffer */
387 up.src = cd_ringbuf + offset;
388 offset = offset + up44k1(&up);
389 }
390 else
391 {
392 /* two portions */
393 sz = sizeof(cd_ringbuf) - offset;
394 wmemcpy(cd_sparebuf, cd_ringbuf + offset, sz);
395 wmemcpy(cd_sparebuf + sz, cd_ringbuf + 0, 1880 - sz);
396 offset = 1880 - sz;
397 up.src = cd_sparebuf;
398 up44k1(&up);
399 }
400
401 /* upsample 44k1 -> 48k0 */
402 wmemcpy(bufptr + 0, cd_rendered_left + 0, 512);
403 wmemcpy(bufptr + 512, cd_rendered_right + 0, 512);
404 wmemcpy(bufptr + 1024, cd_rendered_left + 256, 512);
405 wmemcpy(bufptr + 1536, cd_rendered_right + 256, 512);
406 }
407 else
408 {
409 /* paused, send mute */
410 memset(bufptr, '\0', 2048);
411 }
412
413 CpuResumeIntr(intr_state);
414
415 if ((offset / SECTOR_SIZE) != last_read)
416 {
417 /* read another sector.. */
418 if (read_sectors(cd_ringbuf + (last_read * SECTOR_SIZE), cdda_pos, 1) != 1)
419 {
420 printf("failed to read 1 sector\n");
421 break;
422 }
423
424 last_read = (offset / SECTOR_SIZE);
425 cdda_pos++;
426 }
427 }
428
430
431 /* notify cdda ended */
432 call_client_callback(AUDSRV_CDDA_CALLBACK);
433}
434
439{
440 if (cd_playing == 0)
441 {
442 /* cdrom not playing */
443 return 0;
444 }
445
446 return cdda_pos;
447}
448
453{
454 if (cd_playing == 0)
455 {
456 /* cdrom not playing */
457 return 0;
458 }
459
460 return cdda_pos - cdda_play_start;
461}
462
472int audsrv_cd_play_sectors(int start, int end)
473{
474 DPRINTF("cd_play_sectors: %d %d\n", start, end);
475
476 if (initialize_cdda() < 0)
477 {
478 DPRINTF("initialized cdda failed\n");
479 return AUDSRV_ERR_NOT_INITIALIZED; //FIXME
480 }
481
482 /* stop previous track (and delete running thread) */
484
485 cdda_play_start = start;
486 cdda_play_end = end;
487 cdda_pos = start;
488
489 DPRINTF("creating cdda feed thread\n");
490
491 /* .. and start a new one! */
493 if (cdda_play_tid < 0)
494 {
495 return AUDSRV_ERR_OUT_OF_MEMORY;
496 }
497
498 printf("cdda thread 0x%x started\n", cdda_play_tid);
499
500 cd_playing = 1;
501 return AUDSRV_ERR_NOERROR;
502}
503
508int audsrv_play_cd(int track)
509{
510 int type;
511 int ret;
512 int start, end;
513
514 printf("request to play track %d\n", track);
515
516 if (initialize_cdda() < 0)
517 {
518 DPRINTF("initialized cdda failed\n");
519 return AUDSRV_ERR_NOT_INITIALIZED; //FIXME
520 }
521
522 if (track < 1 || track > toc.num_tracks)
523 {
524 /* invalid track selected */
525 return AUDSRV_ERR_ARGS;
526 }
527
528 type = sceCdGetDiskType();
529 if (track == 1 && (type == 11 || type == 0x13))
530 {
531 /* first track is data */
532 DPRINTF("request to play data track\n");
533 return AUDSRV_ERR_ARGS;
534 }
535
536 start = audsrv_get_track_offset(track - 1);
537 end = audsrv_get_track_offset(track);
538
539 if (start < 0 || end < 0 || end < start)
540 {
541 DPRINTF("invalid track offsets %d, %d\n", start, end);
542 return AUDSRV_ERR_ARGS; //FIXME:
543 }
544
545 ret = audsrv_cd_play_sectors(start, end);
546
547 /* core0 input (known as Evilo's patch #1) */
548 sceSdSetParam(SD_CORE_0 | SD_PARAM_BVOLL, 0x7fff);
549 sceSdSetParam(SD_CORE_0 | SD_PARAM_BVOLR, 0x7fff);
550
551 /* set master volume for core 0 */
552 sceSdSetParam(SD_CORE_0 | SD_PARAM_MVOLL, MAX_VOLUME);
553 sceSdSetParam(SD_CORE_0 | SD_PARAM_MVOLR, MAX_VOLUME);
554
555 return ret;
556}
557
565{
567
568 /* stop playing thread */
569 if (cdda_play_tid >= 0)
570 {
571 TerminateThread(cdda_play_tid);
572 DeleteThread(cdda_play_tid);
573 cdda_play_tid = -1;
574 }
575
576 return 0;
577}
578
static void cdda_procedure(void *arg)
Definition cdrom.c:316
static unsigned char raw_toc[3000]
Definition cdrom.c:54
int audsrv_get_numtracks()
Definition cdrom.c:205
static volatile int cdda_pos
Definition cdrom.c:46
static volatile int cd_paused
Definition cdrom.c:42
int audsrv_cd_resume()
Definition cdrom.c:307
int audsrv_get_cd_type()
Definition cdrom.c:102
static int cdda_play_start
Definition cdrom.c:48
static int cd_transfer_sema
Definition cdrom.c:57
int audsrv_cd_pause()
Definition cdrom.c:298
static int cdda_play_tid
Definition cdrom.c:44
static int cdda_play_end
Definition cdrom.c:50
static int cd_transfer_complete(void *arg)
Definition cdrom.c:91
int audsrv_play_cd(int track)
Definition cdrom.c:508
static int cd_playing
Definition cdrom.c:40
static void audsrv_stop_cd_stream()
Definition cdrom.c:283
int audsrv_get_trackpos()
Definition cdrom.c:452
static int read_sectors(void *dest, int sector, int count)
Definition cdrom.c:247
static int cdda_initialized
Definition cdrom.c:38
int audsrv_get_cdpos()
Definition cdrom.c:438
int audsrv_cd_play_sectors(int start, int end)
Definition cdrom.c:472
static cdda_toc toc
Definition cdrom.c:52
int audsrv_stop_cd()
Definition cdrom.c:564
int audsrv_get_track_offset(int track)
Definition cdrom.c:220
int audsrv_get_cd_status()
Definition cdrom.c:118
static int process_toc()
Definition cdrom.c:126
#define AUDSRV_ERR_NOERROR
Definition audsrv.h:28
#define MAX_VOLUME
Definition audsrv.h:25
int CpuResumeIntr(int state)
Definition intrman.c:227
int CpuSuspendIntr(int *state)
Definition intrman.c:205
int create_thread(void *func, int priority, void *param)
Definition common.c:34
int sceCdGetToc(u8 *toc)
Definition cdi.c:57
int sceCdInit(int mode)
Definition cdi.c:64
int sceCdStatus(void)
Definition cdi.c:152
int sceCdDiskReady(int mode)
Definition cdi.c:30
int sceCdGetDiskType(void)
Definition cdi.c:35
int sceCdSync(int mode)
Definition cdi.c:109
@ SCECdSpinNom
int sceCdTrayReq(int param, u32 *traychk)
Definition cdi.c:162
upsampler_t find_upsampler(int freq, int bits, int channels)
Definition upsamplers.c:636
u32 count
start sector of fragmented bd/file