18d2947e436d4a6354c3c970c9df8bd2cd929d92
[platform/upstream/SDL.git] / src / audio / psp / SDL_pspaudio.c
1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22
23 #if SDL_AUDIO_DRIVER_PSP
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <malloc.h>
29
30 #include "SDL_audio.h"
31 #include "SDL_error.h"
32 #include "SDL_timer.h"
33 #include "../SDL_audiomem.h"
34 #include "../SDL_audio_c.h"
35 #include "../SDL_audiodev_c.h"
36 #include "../SDL_sysaudio.h"
37 #include "SDL_pspaudio.h"
38
39 #include <pspaudio.h>
40 #include <pspthreadman.h>
41
42 /* The tag name used by PSP audio */
43 #define PSPAUD_DRIVER_NAME         "psp"
44
45 static int
46 PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
47 {
48     int format, mixlen, i;
49     this->hidden = (struct SDL_PrivateAudioData *)
50         SDL_malloc(sizeof(*this->hidden));
51     if (this->hidden == NULL) {
52         return SDL_OutOfMemory();
53     }
54     SDL_memset(this->hidden, 0, sizeof(*this->hidden));
55     switch (this->spec.format & 0xff) {
56         case 8:
57         case 16:
58             this->spec.format = AUDIO_S16LSB;
59             break;
60         default:
61             return SDL_SetError("Unsupported audio format");
62     }
63
64     /* The sample count must be a multiple of 64. */
65     this->spec.samples = PSP_AUDIO_SAMPLE_ALIGN(this->spec.samples);
66     this->spec.freq = 44100;
67
68     /* Update the fragment size as size in bytes. */
69 /*  SDL_CalculateAudioSpec(this->spec); MOD */
70     switch (this->spec.format) {
71     case AUDIO_U8:
72         this->spec.silence = 0x80;
73         break;
74     default:
75         this->spec.silence = 0x00;
76         break;
77     }
78     this->spec.size = SDL_AUDIO_BITSIZE(this->spec.format) / 8;
79     this->spec.size *= this->spec.channels;
80     this->spec.size *= this->spec.samples;
81
82 /* ========================================== */
83
84     /* Allocate the mixing buffer.  Its size and starting address must
85        be a multiple of 64 bytes.  Our sample count is already a multiple of
86        64, so spec->size should be a multiple of 64 as well. */
87     mixlen = this->spec.size * NUM_BUFFERS;
88     this->hidden->rawbuf = (Uint8 *) memalign(64, mixlen);
89     if (this->hidden->rawbuf == NULL) {
90         return SDL_SetError("Couldn't allocate mixing buffer");
91     }
92
93     /* Setup the hardware channel. */
94     if (this->spec.channels == 1) {
95         format = PSP_AUDIO_FORMAT_MONO;
96     } else {
97         format = PSP_AUDIO_FORMAT_STEREO;
98     }
99     this->hidden->channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, this->spec.samples, format);
100     if (this->hidden->channel < 0) {
101         free(this->hidden->rawbuf);
102         this->hidden->rawbuf = NULL;
103         return SDL_SetError("Couldn't reserve hardware channel");
104     }
105
106     memset(this->hidden->rawbuf, 0, mixlen);
107     for (i = 0; i < NUM_BUFFERS; i++) {
108         this->hidden->mixbufs[i] = &this->hidden->rawbuf[i * this->spec.size];
109     }
110
111     this->hidden->next_buffer = 0;
112     return 0;
113 }
114
115 static void PSPAUD_PlayDevice(_THIS)
116 {
117     Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
118
119     if (this->spec.channels == 1) {
120         sceAudioOutputBlocking(this->hidden->channel, PSP_AUDIO_VOLUME_MAX, mixbuf);
121     } else {
122         sceAudioOutputPannedBlocking(this->hidden->channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, mixbuf);
123     }
124
125     this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
126 }
127
128 /* This function waits until it is possible to write a full sound buffer */
129 static void PSPAUD_WaitDevice(_THIS)
130 {
131     /* Because we block when sending audio, there's no need for this function to do anything. */
132 }
133 static Uint8 *PSPAUD_GetDeviceBuf(_THIS)
134 {
135     return this->hidden->mixbufs[this->hidden->next_buffer];
136 }
137
138 static void PSPAUD_CloseDevice(_THIS)
139 {
140     if (this->hidden->channel >= 0) {
141         sceAudioChRelease(this->hidden->channel);
142         this->hidden->channel = -1;
143     }
144
145     if (this->hidden->rawbuf != NULL) {
146         free(this->hidden->rawbuf);
147         this->hidden->rawbuf = NULL;
148     }
149 }
150 static void PSPAUD_ThreadInit(_THIS)
151 {
152     /* Increase the priority of this audio thread by 1 to put it
153        ahead of other SDL threads. */
154     SceUID thid;
155     SceKernelThreadInfo status;
156     thid = sceKernelGetThreadId();
157     status.size = sizeof(SceKernelThreadInfo);
158     if (sceKernelReferThreadStatus(thid, &status) == 0) {
159         sceKernelChangeThreadPriority(thid, status.currentPriority - 1);
160     }
161 }
162
163
164 static int
165 PSPAUD_Init(SDL_AudioDriverImpl * impl)
166 {
167
168     /* Set the function pointers */
169     impl->OpenDevice = PSPAUD_OpenDevice;
170     impl->PlayDevice = PSPAUD_PlayDevice;
171     impl->WaitDevice = PSPAUD_WaitDevice;
172     impl->GetDeviceBuf = PSPAUD_GetDeviceBuf;
173     impl->WaitDone = PSPAUD_WaitDevice;
174     impl->CloseDevice = PSPAUD_CloseDevice;
175     impl->ThreadInit = PSPAUD_ThreadInit;
176
177     /* PSP audio device */
178     impl->OnlyHasDefaultOutputDevice = 1;
179 /*
180     impl->HasCaptureSupport = 1;
181
182     impl->OnlyHasDefaultInputDevice = 1;
183 */
184     /*
185     impl->DetectDevices = DSOUND_DetectDevices;
186     impl->Deinitialize = DSOUND_Deinitialize;
187     */
188     return 1;   /* this audio target is available. */
189 }
190
191 AudioBootStrap PSPAUD_bootstrap = {
192     "psp", "PSP audio driver", PSPAUD_Init, 0
193 };
194
195  /* SDL_AUDI */
196
197 #endif /* SDL_AUDIO_DRIVER_PSP */
198
199 /* vi: set ts=4 sw=4 expandtab: */