Logo Search packages:      
Sourcecode: scummvm version File versions

audio.cpp

/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * $URL$
 * $Id$
 *
 */

#include <pspthreadman.h>
#include <pspaudio.h>

#include "common/scummsys.h"
#include "backends/platform/psp/audio.h"

//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */
//#define __PSP_DEBUG_PRINT__ /* For debug printouts */

#include "backends/platform/psp/trace.h"

bool PspAudio::open(uint32 freq, uint32 numOfChannels, uint32 numOfSamples, callbackFunc callback, void *userData) {
      DEBUG_ENTER_FUNC();
      if (_init) {
            PSP_ERROR("audio device already initialized\n");
            return true;
      }

      PSP_DEBUG_PRINT("freq[%d], numOfChannels[%d], numOfSamples[%d], callback[%p], userData[%x]\n",
                  freq, numOfChannels, numOfSamples, callback, (uint32)userData);

      numOfSamples = PSP_AUDIO_SAMPLE_ALIGN(numOfSamples);
      uint32 bufLen = numOfSamples * numOfChannels * NUM_BUFFERS * sizeof(uint16);

      PSP_DEBUG_PRINT("total buffer size[%d]\n", bufLen);

      _buffers[0] = (byte *)memalign(64, bufLen);
      if (!_buffers[0]) {
            PSP_ERROR("failed to allocate memory for audio buffers\n");
            return false;
      }
      memset(_buffers[0], 0, bufLen);     // clean the buffer

      // Fill in the rest of the buffer pointers
      byte *pBuffer = _buffers[0];
      for (int i = 1; i < NUM_BUFFERS; i++) {
            pBuffer += numOfSamples * numOfChannels * sizeof(uint16);
            _buffers[i] = pBuffer;
      }

      // Reserve a HW channel for our audio
      _pspChannel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, numOfSamples, numOfChannels == 2 ? PSP_AUDIO_FORMAT_STEREO : PSP_AUDIO_FORMAT_MONO);
      if (_pspChannel < 0) {
            PSP_ERROR("failed to reserve audio channel\n");
            return false;
      }

      PSP_DEBUG_PRINT("reserved channel[%d] for audio\n", _pspChannel);

      // Save our data
      _numOfChannels = numOfChannels;
      _numOfSamples = numOfSamples;
      _bufferSize = numOfSamples * numOfChannels * sizeof(uint16);      // should be the right size to send the app
      _callback = callback;
      _userData = userData;
      _bufferToFill = 0;
      _bufferToPlay = 0;

      _init = true;
      _paused = true;   // start in paused mode

      threadCreateAndStart("audioThread", PRIORITY_AUDIO_THREAD, STACK_AUDIO_THREAD);     // start the consumer thread

      return true;
}

// The real thread function
void PspAudio::threadFunction() {
      assert(_callback);
      PSP_DEBUG_PRINT_FUNC("audio thread started\n");

      while (_init) {         // Keep looping so long as we haven't been told to stop
            if (_paused)
                  PSP_DEBUG_PRINT("audio thread paused\n");
            while (_paused) { // delay until we stop pausing
                  PspThread::delayMicros(100000);     // 100ms
                  if (!_paused)
                        PSP_DEBUG_PRINT("audio thread unpaused\n");
            }

            PSP_DEBUG_PRINT("remaining samples[%d]\n", _remainingSamples);

            PSP_DEBUG_PRINT("filling buffer[%d]\n", _bufferToFill);
            _callback(_userData, _buffers[_bufferToFill], _bufferSize); // ask mixer to fill in data
            nextBuffer(_bufferToFill);

            PSP_DEBUG_PRINT("playing buffer[%d].\n", _bufferToPlay);
            playBuffer();
            nextBuffer(_bufferToPlay);
      } // while _init

      // destroy everything
      free(_buffers[0]);
      sceAudioChRelease(_pspChannel);
      PSP_DEBUG_PRINT("audio thread exiting. ****************************\n");
}

// Much faster than using %, especially with conditional moves (MIPS)
inline void PspAudio::nextBuffer(int &bufferIdx) {
      DEBUG_ENTER_FUNC();
      bufferIdx++;
      if (bufferIdx >= NUM_BUFFERS)
            bufferIdx = 0;
}

// Don't do it with blocking
inline bool PspAudio::playBuffer() {
      DEBUG_ENTER_FUNC();
      int ret;
      if (_numOfChannels == 1)
            ret = sceAudioOutputBlocking(_pspChannel, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]);
      else
            ret = sceAudioOutputPannedBlocking(_pspChannel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]);

      if (ret < 0) {
            PSP_ERROR("failed to output audio. Error[%d]\n", ret);
            return false;
      }
      return true;
}

void PspAudio::close() {
      PSP_DEBUG_PRINT("close has been called ***************\n");
      _init = false;
}

Generated by  Doxygen 1.6.0   Back to index