1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include <pspthreadman.h>
24 #include <pspaudio.h>
25
26 #include "common/scummsys.h"
27 #include "backends/platform/psp/audio.h"
28
29 //#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */
30 //#define __PSP_DEBUG_PRINT__ /* For debug printouts */
31
32 #include "backends/platform/psp/trace.h"
33
open(uint32 freq,uint32 numOfChannels,uint32 numOfSamples,callbackFunc callback,void * userData)34 bool PspAudio::open(uint32 freq, uint32 numOfChannels, uint32 numOfSamples, callbackFunc callback, void *userData) {
35 DEBUG_ENTER_FUNC();
36 if (_init) {
37 PSP_ERROR("audio device already initialized\n");
38 return true;
39 }
40
41 PSP_DEBUG_PRINT("freq[%d], numOfChannels[%d], numOfSamples[%d], callback[%p], userData[%x]\n",
42 freq, numOfChannels, numOfSamples, callback, (uint32)userData);
43
44 numOfSamples = PSP_AUDIO_SAMPLE_ALIGN(numOfSamples);
45 uint32 bufLen = numOfSamples * numOfChannels * NUM_BUFFERS * sizeof(uint16);
46
47 PSP_DEBUG_PRINT("total buffer size[%d]\n", bufLen);
48
49 _buffers[0] = (byte *)memalign(64, bufLen);
50 if (!_buffers[0]) {
51 PSP_ERROR("failed to allocate memory for audio buffers\n");
52 return false;
53 }
54 memset(_buffers[0], 0, bufLen); // clean the buffer
55
56 // Fill in the rest of the buffer pointers
57 byte *pBuffer = _buffers[0];
58 for (int i = 1; i < NUM_BUFFERS; i++) {
59 pBuffer += numOfSamples * numOfChannels * sizeof(uint16);
60 _buffers[i] = pBuffer;
61 }
62
63 // Reserve a HW channel for our audio
64 _pspChannel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, numOfSamples, numOfChannels == 2 ? PSP_AUDIO_FORMAT_STEREO : PSP_AUDIO_FORMAT_MONO);
65 if (_pspChannel < 0) {
66 PSP_ERROR("failed to reserve audio channel\n");
67 return false;
68 }
69
70 PSP_DEBUG_PRINT("reserved channel[%d] for audio\n", _pspChannel);
71
72 // Save our data
73 _numOfChannels = numOfChannels;
74 _numOfSamples = numOfSamples;
75 _bufferSize = numOfSamples * numOfChannels * sizeof(uint16); // should be the right size to send the app
76 _callback = callback;
77 _userData = userData;
78 _bufferToFill = 0;
79 _bufferToPlay = 0;
80
81 _init = true;
82 _paused = true; // start in paused mode
83
84 threadCreateAndStart("audioThread", PRIORITY_AUDIO_THREAD, STACK_AUDIO_THREAD); // start the consumer thread
85
86 return true;
87 }
88
89 // The real thread function
threadFunction()90 void PspAudio::threadFunction() {
91 assert(_callback);
92 PSP_DEBUG_PRINT_FUNC("audio thread started\n");
93
94 while (_init) { // Keep looping so long as we haven't been told to stop
95 if (_paused)
96 PSP_DEBUG_PRINT("audio thread paused\n");
97 while (_paused) { // delay until we stop pausing
98 PspThread::delayMicros(100000); // 100ms
99 if (!_paused)
100 PSP_DEBUG_PRINT("audio thread unpaused\n");
101 }
102
103 PSP_DEBUG_PRINT("filling buffer[%d]\n", _bufferToFill);
104 _callback(_userData, _buffers[_bufferToFill], _bufferSize); // ask mixer to fill in data
105 nextBuffer(_bufferToFill);
106
107 PSP_DEBUG_PRINT("playing buffer[%d].\n", _bufferToPlay);
108 playBuffer();
109 nextBuffer(_bufferToPlay);
110 } // while _init
111
112 // destroy everything
113 free(_buffers[0]);
114 sceAudioChRelease(_pspChannel);
115 PSP_DEBUG_PRINT("audio thread exiting. ****************************\n");
116 }
117
118 // Much faster than using %, especially with conditional moves (MIPS)
nextBuffer(int & bufferIdx)119 inline void PspAudio::nextBuffer(int &bufferIdx) {
120 DEBUG_ENTER_FUNC();
121 bufferIdx++;
122 if (bufferIdx >= NUM_BUFFERS)
123 bufferIdx = 0;
124 }
125
126 // Don't do it with blocking
playBuffer()127 inline bool PspAudio::playBuffer() {
128 DEBUG_ENTER_FUNC();
129 int ret;
130 if (_numOfChannels == 1)
131 ret = sceAudioOutputBlocking(_pspChannel, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]);
132 else
133 ret = sceAudioOutputPannedBlocking(_pspChannel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]);
134
135 if (ret < 0) {
136 PSP_ERROR("failed to output audio. Error[%d]\n", ret);
137 return false;
138 }
139 return true;
140 }
141
close()142 void PspAudio::close() {
143 PSP_DEBUG_PRINT("close has been called ***************\n");
144 _init = false;
145 }
146