PS2SDK
PS2 Homebrew Libraries
adpcm.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 <libsd.h>
22 #include <sysclib.h>
23 
24 #include <audsrv.h>
25 #include "audsrv_internal.h"
26 #include "common.h"
27 #include "rpc_server.h"
28 #include "spu.h"
29 #include "debug_printf.h"
30 
31 typedef struct adpcm_list_t
32 {
33  struct adpcm_list_t *next;
34 
35  int id;
36  int pitch;
37  int loop;
38  int channels;
39  int size;
40  int spu2_addr;
41 } adpcm_list_t;
42 
43 static adpcm_list_t *adpcm_list_head = 0;
44 static adpcm_list_t *adpcm_list_tail = 0;
45 
46 static u32 sbuffer[16] __attribute__((aligned(16)));
47 
50 {
51  void *buffer;
52  int OldState;
53 
54  CpuSuspendIntr(&OldState);
55  buffer = AllocSysMemory(ALLOC_FIRST, sizeof(adpcm_list_t), NULL);
56  CpuResumeIntr(OldState);
57 
58  return buffer;
59 }
60 
62 static void free_all_samples()
63 {
64  adpcm_list_t *p, *q;
65  int OldState;
66 
67  CpuSuspendIntr(&OldState);
68  for (p = adpcm_list_head; p != NULL; p = q)
69  {
70  q = p->next;
71  FreeSysMemory(p);
72  }
73 
74  adpcm_list_head = NULL;
75  adpcm_list_tail = NULL;
76  CpuResumeIntr(OldState);
77 }
78 
84 int free_sample(u32 id)
85 {
86  adpcm_list_t *adpcm = adpcm_list_head;
87  adpcm_list_t *parent = NULL;
88 
89  while (adpcm != NULL)
90  {
91  if (adpcm->id == id)
92  {
93  break;
94  }
95 
96  parent = adpcm;
97  adpcm = adpcm->next;
98  }
99 
100  if (adpcm == NULL)
101  {
102  return AUDSRV_ERR_NOERROR;
103  }
104 
105  if (parent != NULL)
106  parent->next = adpcm->next;
107 
108  if (adpcm_list_head == adpcm)
109  adpcm_list_head = adpcm->next;
110 
111  if (adpcm_list_tail == adpcm)
112  adpcm_list_tail = parent;
113 
114  int OldState;
115  CpuSuspendIntr(&OldState);
116  FreeSysMemory(adpcm);
117  CpuResumeIntr(OldState);
118 
119  return AUDSRV_ERR_NOERROR;
120 }
121 
126 static adpcm_list_t *adpcm_loaded(int id)
127 {
128  adpcm_list_t *cur = adpcm_list_head;
129 
130  while (cur != NULL)
131  {
132  if (cur->id == id)
133  {
134  return cur;
135  }
136 
137  cur = cur->next;
138  }
139 
140  return NULL;
141 }
142 
147 static void audsrv_read_adpcm_header(adpcm_list_t *adpcm, const u32 *buffer)
148 {
149  adpcm->pitch = buffer[2];
150  adpcm->loop = (buffer[1] >> 16) & 0xFF;
151  adpcm->channels = (buffer[1] >> 8) & 0xFF;
152 }
153 
160 void *audsrv_load_adpcm(u32 *buffer, int size, int id)
161 {
162  adpcm_list_t *adpcm;
163 
164  adpcm = adpcm_loaded(id);
165  if (adpcm == NULL)
166  {
167  int spu2_addr = 0x5010; /* Need to change this so it considers to PCM streaming space usage :) */
168  if (adpcm_list_tail != NULL)
169  {
170  spu2_addr = adpcm_list_tail->spu2_addr + adpcm_list_tail->size;
171  }
172  if (spu2_addr + size - 16 > 2097152)
173  {
174  sbuffer[0] = -AUDSRV_ERR_OUT_OF_MEMORY;
175  return sbuffer;
176  }
177 
178  adpcm = alloc_new_sample();
179  adpcm->id = id;
180  adpcm->spu2_addr = spu2_addr;
181  adpcm->size = size - 16; /* header is 16 bytes */
182  adpcm->next = NULL;
183 
184  audsrv_read_adpcm_header(adpcm, buffer);
185 
186  if (adpcm_list_head == NULL)
187  {
188  /* first entry ever! yay! */
189  adpcm_list_head = adpcm;
190  adpcm_list_tail = adpcm_list_head;
191  }
192  else
193  {
194  /* add at the end of the list */
195  adpcm_list_tail->next = adpcm;
196  adpcm_list_tail = adpcm;
197  }
198 
199  /* DMA from IOP to SPU2 */
200  sceSdVoiceTrans(AUDSRV_VOICE_DMA_CH, SD_TRANS_WRITE | SD_TRANS_MODE_DMA, ((u8*)buffer)+16, (u32*)adpcm->spu2_addr, adpcm->size);
201  sceSdVoiceTransStatus(AUDSRV_VOICE_DMA_CH, 1);
202  }
203 
204  sbuffer[0] = 0;
205  sbuffer[1] = adpcm->pitch;
206  sbuffer[2] = adpcm->loop;
207  sbuffer[3] = adpcm->channels;
208  return sbuffer;
209 }
210 
211 int audsrv_is_adpcm_playing(int ch, u32 id)
212 {
213  u32 endx;
214  adpcm_list_t *a;
215 
216  if (ch > 24)
217  return 0;
218 
219  endx = sceSdGetSwitch(SD_CORE_1 | SD_SWITCH_ENDX);
220  if ((endx & (1 << ch)) != 0)
221  return 0;
222 
223  a = adpcm_loaded(id);
224  if (a == NULL)
225  {
226  /* bad joke */
227  return AUDSRV_ERR_ARGS;
228  }
229 
230  return a->spu2_addr == sceSdGetAddr(SD_CORE_1 | (ch << 1) | SD_VOICE_START);
231 }
232 
233 static int audsrv_adpcm_alloc_channel(void)
234 {
235  int i, channel;
236  u32 endx;
237 
238  endx = sceSdGetSwitch(SD_CORE_1 | SD_SWITCH_ENDX);
239  if (endx == 0)
240  {
241  /* all channels are occupied */
242  return -AUDSRV_ERR_NO_MORE_CHANNELS;
243  }
244 
245  /* find first channel available */
246  i = 1;
247  channel = -1;
248  while ((channel < 0) && (i < 24))
249  {
250  if (endx & (1 << i))
251  {
252  channel = i;
253  }
254 
255  i++;
256  }
257 
258  if (channel == -1)
259  {
260  /* cannot find a single channel free */
261  return -AUDSRV_ERR_NO_MORE_CHANNELS;
262  }
263 
264  return channel;
265 }
266 
277 int audsrv_ch_play_adpcm(int ch, u32 id)
278 {
279  int channel;
280  u32 endx;
281  adpcm_list_t *a;
282 
283  a = adpcm_loaded(id);
284  if (a == NULL)
285  {
286  /* bad joke */
287  return AUDSRV_ERR_ARGS;
288  }
289 
290  /* sample was loaded */
291  if (ch >= 0 && ch < 24)
292  {
293  endx = sceSdGetSwitch(SD_CORE_1 | SD_SWITCH_ENDX);
294  if (!(endx & (1 << ch)))
295  {
296  /* Channel in use. */
297  return -AUDSRV_ERR_NO_MORE_CHANNELS;
298  }
299 
300  channel = ch;
301  }
302  else
303  {
304  channel = audsrv_adpcm_alloc_channel();
305  if (channel < 0)
306  return channel;
307  }
308 
309  sceSdSetParam(SD_CORE_1 | (channel << 1) | SD_VPARAM_PITCH, a->pitch);
310  sceSdSetAddr(SD_CORE_1 | (channel << 1) | SD_VOICE_START, a->spu2_addr);
311  sceSdSetSwitch(SD_CORE_1 | SD_SWITCH_KON, (1 << channel));
312  return channel;
313 }
314 
320 {
321  int voice;
322 
323  printf("audsrv_adpcm_init()\n");
324 
325  for (voice = 0; voice < 24; voice++)
326  {
327  sceSdSetSwitch(SD_CORE_1 | SD_SWITCH_KOFF, (1 << voice));
328  sceSdSetParam(SD_CORE_1 | (voice << 1) | SD_VPARAM_VOLL, 0x3fff);
329  sceSdSetParam(SD_CORE_1 | (voice << 1) | SD_VPARAM_VOLR, 0x3fff);
330  }
331 
332  if (adpcm_list_head != NULL)
333  {
334  /* called second time, after samples were already uploaded */
336  }
337 
338  return AUDSRV_ERR_NOERROR;
339 }
340 
347 int audsrv_adpcm_set_volume(int ch, int voll, int volr)
348 {
349  if (voll < 0 || voll > MAX_VOLUME || volr < 0 || volr > MAX_VOLUME)
350  {
351  /* bad joke */
352  return AUDSRV_ERR_ARGS;
353  }
354 
355  sceSdSetParam(SD_CORE_1 | (ch << 1) | SD_VPARAM_VOLL, voll);
356  sceSdSetParam(SD_CORE_1 | (ch << 1) | SD_VPARAM_VOLR, volr);
357 
358  return AUDSRV_ERR_NOERROR;
359 }
360 
rpc_server.h
thbase.h
sysclib.h
alloc_new_sample
static adpcm_list_t * alloc_new_sample(void)
Definition: adpcm.c:49
CpuSuspendIntr
int CpuSuspendIntr(int *state)
Definition: intrman.c:195
loadcore.h
free_sample
int free_sample(u32 id)
Definition: adpcm.c:84
common.h
__attribute__
static u32 sbuffer[16] __attribute__((aligned(16)))
Definition: netcnfif.c:19
audsrv_load_adpcm
void * audsrv_load_adpcm(u32 *buffer, int size, int id)
Definition: adpcm.c:160
thsemap.h
audsrv_read_adpcm_header
static void audsrv_read_adpcm_header(adpcm_list_t *adpcm, const u32 *buffer)
Definition: adpcm.c:147
adpcm_loaded
static adpcm_list_t * adpcm_loaded(int id)
Definition: adpcm.c:126
stdio.h
audsrv_is_adpcm_playing
int audsrv_is_adpcm_playing(int ch, audsrv_adpcm_t *adpcm)
Definition: audsrv_rpc.c:487
audsrv_adpcm_init
int audsrv_adpcm_init()
Definition: adpcm.c:319
MAX_VOLUME
#define MAX_VOLUME
Definition: audsrv.h:25
CpuResumeIntr
int CpuResumeIntr(int state)
Definition: intrman.c:217
spu.h
sysmem.h
adpcm_list_t
Definition: adpcm.c:31
__attribute__
Definition: gif_registers.h:38
AUDSRV_ERR_NOERROR
#define AUDSRV_ERR_NOERROR
Definition: audsrv.h:28
intrman.h
audsrv_adpcm_set_volume
int audsrv_adpcm_set_volume(int ch, int voll, int volr)
Definition: adpcm.c:347
free_all_samples
static void free_all_samples()
Definition: adpcm.c:62
audsrv_internal.h
audsrv_ch_play_adpcm
int audsrv_ch_play_adpcm(int ch, u32 id)
Definition: adpcm.c:277