PS2SDK
PS2 Homebrew Libraries
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 */
38 static int cdda_initialized = 0;
40 static int cd_playing = 0;
42 static volatile int cd_paused = 0;
44 static int cdda_play_tid = -1;
46 static volatile int cdda_pos = 0;
48 static int cdda_play_start = 0;
50 static int cdda_play_end = 0;
52 static cdda_toc toc;
54 static unsigned char raw_toc[3000];
55 
57 static int cd_transfer_sema = -1;
58 
60 static u8 cd_ringbuf[SECTOR_SIZE*8] __attribute__((aligned (16)));
62 static u8 cd_sparebuf[1880] __attribute__((aligned (16)));
63 static u8 core0_buf[0x1000] __attribute__((aligned (16)));
64 
65 static short cd_rendered_left[512];
66 static short cd_rendered_right[512];
67 
68 static 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 
91 static 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 
126 static 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 
157 static int initialize_cdda()
158 {
159  int err, dummy, type;
160 
161  if (cdda_initialized)
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 
182  sceCdDiskReady(0);
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 
197  cdda_initialized = 1;
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 
247 static 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 */
261  sceCdDiskReady(0);
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 
316 static 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 
429  audsrv_stop_cd();
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 
472 int 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) */
483  audsrv_stop_cd();
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 
508 int 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 
sceCdlLOCCD::sector
u8 sector
Definition: libcdvd-common.h:228
process_toc
static int process_toc()
Definition: cdrom.c:126
cdrom.h
rpc_server.h
audsrv_cd_resume
int audsrv_cd_resume()
Definition: cdrom.c:307
cdda_play_tid
static int cdda_play_tid
Definition: cdrom.c:44
raw_toc
static unsigned char raw_toc[3000]
Definition: cdrom.c:54
audsrv_get_cd_type
int audsrv_get_cd_type()
Definition: cdrom.c:102
sceCdSync
int sceCdSync(int mode)
Definition: cdi.c:109
sceCdTrayReq
int sceCdTrayReq(int param, u32 *traychk)
Definition: cdi.c:162
thbase.h
sysclib.h
cd_playing
static int cd_playing
Definition: cdrom.c:40
audsrv_cd_pause
int audsrv_cd_pause()
Definition: cdrom.c:298
audsrv_stop_cd_stream
static void audsrv_stop_cd_stream()
Definition: cdrom.c:283
toc
static cdda_toc toc
Definition: cdrom.c:52
sceCdGetDiskType
int sceCdGetDiskType(void)
Definition: cdi.c:35
sceCdlLOCCD::second
u8 second
Definition: libcdvd-common.h:226
CpuSuspendIntr
int CpuSuspendIntr(int *state)
Definition: intrman.c:195
cdda_toc
Definition: cdrom.h:20
cdda_pos
static volatile int cdda_pos
Definition: cdrom.c:46
loadcore.h
cdda_play_end
static int cdda_play_end
Definition: cdrom.c:50
common.h
audsrv_get_track_offset
int audsrv_get_track_offset(int track)
Definition: cdrom.c:220
audsrv_stop_cd
int audsrv_stop_cd()
Definition: cdrom.c:564
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
cdvdman.h
hw.h
read_sectors
static int read_sectors(void *dest, int sector, int count)
Definition: cdrom.c:247
thsemap.h
cd_transfer_sema
static int cd_transfer_sema
Definition: cdrom.c:57
cdda_procedure
static void cdda_procedure(void *arg)
Definition: cdrom.c:316
audsrv_play_cd
int audsrv_play_cd(int track)
Definition: cdrom.c:508
audsrv_get_cdpos
int audsrv_get_cdpos()
Definition: cdrom.c:438
stdio.h
cdda_initialized
static int cdda_initialized
Definition: cdrom.c:38
MAX_VOLUME
#define MAX_VOLUME
Definition: audsrv.h:25
sceCdInit
int sceCdInit(int mode)
Definition: cdi.c:64
sceCdlLOCCD::track
u8 track
Definition: libcdvd-common.h:230
CpuResumeIntr
int CpuResumeIntr(int state)
Definition: intrman.c:217
spu.h
audsrv_cd_play_sectors
int audsrv_cd_play_sectors(int start, int end)
Definition: cdrom.c:472
audsrv_get_trackpos
int audsrv_get_trackpos()
Definition: cdrom.c:452
sysmem.h
audsrv_get_cd_status
int audsrv_get_cd_status()
Definition: cdrom.c:118
__attribute__
Definition: gif_registers.h:38
sceCdlLOCCD::minute
u8 minute
Definition: libcdvd-common.h:224
__attribute__
static u8 cd_ringbuf[SECTOR_SIZE *8] __attribute__((aligned(16)))
Definition: netcnfif.c:19
sceCdRMode
Definition: libcdvd-common.h:233
AUDSRV_ERR_NOERROR
#define AUDSRV_ERR_NOERROR
Definition: audsrv.h:28
rpc_client.h
upsamplers.h
upsample_t
Definition: upsamplers.h:18
find_upsampler
upsampler_t find_upsampler(int freq, int bits, int channels)
Definition: upsamplers.c:636
intrman.h
sceCdDiskReady
int sceCdDiskReady(int mode)
Definition: cdi.c:30
audsrv_get_numtracks
int audsrv_get_numtracks()
Definition: cdrom.c:205
cd_transfer_complete
static int cd_transfer_complete(void *arg)
Definition: cdrom.c:91
sceCdGetToc
int sceCdGetToc(u8 *toc)
Definition: cdi.c:57
cd_paused
static volatile int cd_paused
Definition: cdrom.c:42
cdda_play_start
static int cdda_play_start
Definition: cdrom.c:48
sceCdStatus
int sceCdStatus(void)
Definition: cdi.c:152
SCECdSpinNom
@ SCECdSpinNom
Definition: libcdvd-common.h:46
create_thread
int create_thread(void(*func)(void *param), int priority, void *param)
Definition: common.c:34