188 lines
4.8 KiB
C++
188 lines
4.8 KiB
C++
/* 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 "stdafx.h"
|
|
#include "common/scummsys.h"
|
|
|
|
#include "gp32std.h"
|
|
#include "gp32std_sound.h"
|
|
|
|
#define GP32_TIMER_AUDIO_IDX 0
|
|
|
|
// Global variables
|
|
static volatile unsigned int frame = 0;
|
|
static volatile unsigned int *soundPos = 0;
|
|
static volatile int idx_buf;
|
|
static volatile unsigned int shiftVal = 0;
|
|
static void *buffer;
|
|
static GPSOUNDBUF soundBuf;
|
|
|
|
// This routine gets called by the timer interrupt and
|
|
// polls the current playing position within the buffer.
|
|
|
|
static void soundTimer() {
|
|
static int locked = false;
|
|
|
|
if (locked) {
|
|
return;
|
|
}
|
|
|
|
locked = true;
|
|
|
|
unsigned int sampleshiftVal = soundBuf.samples << shiftVal;
|
|
unsigned int t = (((unsigned int)(*soundPos) - (unsigned int)buffer) >> shiftVal) >= soundBuf.samples ? 1 : 0;
|
|
if (t != frame) {
|
|
unsigned int offs = ((frame == 1) ? (sampleshiftVal) : 0);
|
|
//memset((uint8 *)buffer + offs, 0, sampleshiftVal);
|
|
soundBuf.callback(soundBuf.userdata, (uint8 *)((unsigned int)buffer + offs), sampleshiftVal);
|
|
frame = t;
|
|
{
|
|
// Play silence
|
|
register uint16 *d = (uint16 *)((uint8 *)buffer + offs); // alignment-safe
|
|
register uint32 max = (uint32)((uint8 *)buffer + offs + sampleshiftVal);
|
|
do {
|
|
*d++ ^= 0x8000; // 1
|
|
*d++ ^= 0x8000; // 2
|
|
*d++ ^= 0x8000; // 3
|
|
*d++ ^= 0x8000; // 4
|
|
*d++ ^= 0x8000; // 5
|
|
*d++ ^= 0x8000; // 6
|
|
*d++ ^= 0x8000; // 7
|
|
*d++ ^= 0x8000; // 8
|
|
*d++ ^= 0x8000; // 9
|
|
*d++ ^= 0x8000; // 10
|
|
*d++ ^= 0x8000; // 11
|
|
*d++ ^= 0x8000; // 12
|
|
*d++ ^= 0x8000; // 13
|
|
*d++ ^= 0x8000; // 14
|
|
*d++ ^= 0x8000; // 15
|
|
*d++ ^= 0x8000; // 16
|
|
*d++ ^= 0x8000; // 17
|
|
*d++ ^= 0x8000; // 18
|
|
*d++ ^= 0x8000; // 19
|
|
*d++ ^= 0x8000; // 20
|
|
*d++ ^= 0x8000; // 21
|
|
*d++ ^= 0x8000; // 22
|
|
*d++ ^= 0x8000; // 23
|
|
*d++ ^= 0x8000; // 24
|
|
*d++ ^= 0x8000; // 25
|
|
*d++ ^= 0x8000; // 26
|
|
*d++ ^= 0x8000; // 27
|
|
*d++ ^= 0x8000; // 28
|
|
*d++ ^= 0x8000; // 29
|
|
*d++ ^= 0x8000; // 30
|
|
*d++ ^= 0x8000; // 31
|
|
*d++ ^= 0x8000; // 32
|
|
} while ((uint32)d < max);
|
|
}
|
|
}
|
|
|
|
locked = false;
|
|
}
|
|
|
|
int gp_soundBufStart(GPSOUNDBUF *sb) {
|
|
int bufferSize = 0;
|
|
|
|
PCM_SR gpFreq = PCM_S11;
|
|
PCM_BIT gpFormat = PCM_16BIT;
|
|
|
|
frame = 0;
|
|
|
|
// Copy the structure
|
|
memcpy(&soundBuf, sb, sizeof(GPSOUNDBUF));
|
|
|
|
// Calculate size of a single sample in bytes
|
|
// and a corresponding shift value
|
|
shiftVal = 0;
|
|
|
|
switch (soundBuf.format) {
|
|
case 8:
|
|
gpFormat = PCM_8BIT;
|
|
break;
|
|
case 16:
|
|
gpFormat = PCM_16BIT;
|
|
shiftVal++;
|
|
break;
|
|
}
|
|
|
|
switch (soundBuf.freq) {
|
|
case 11025:
|
|
if (soundBuf.channels == 2) {
|
|
gpFreq = PCM_S11;
|
|
shiftVal++;
|
|
} else
|
|
gpFreq = PCM_M11;
|
|
break;
|
|
case 22050:
|
|
if (soundBuf.channels == 2) {
|
|
gpFreq = PCM_S22;
|
|
shiftVal++;
|
|
} else
|
|
gpFreq = PCM_M22;
|
|
break;
|
|
case 44100:
|
|
if (soundBuf.channels == 2) {
|
|
gpFreq = PCM_S44;
|
|
shiftVal++;
|
|
} else
|
|
gpFreq = PCM_M44;
|
|
break;
|
|
}
|
|
|
|
soundBuf.samplesize = 1 << shiftVal;
|
|
|
|
// Allocate memory for the playing buffer
|
|
bufferSize = soundBuf.samplesize * soundBuf.samples * 2;
|
|
buffer = malloc(bufferSize);
|
|
|
|
// Clear the buffer
|
|
uint16 *tmpBuf = (uint16 *)buffer;
|
|
for (int i = 0; i < bufferSize / 2; i++)
|
|
tmpBuf[i] = 0x8000;
|
|
|
|
// Frequency of the timer interrupt which polls the playing position
|
|
// FIXME: This frequency should not be multiplied by 4.
|
|
soundBuf.pollfreq = 4 * (2 * soundBuf.freq) / soundBuf.samples;
|
|
|
|
// Set timer interrupt
|
|
if (GpTimerOptSet(GP32_TIMER_AUDIO_IDX, soundBuf.pollfreq, 0, soundTimer) == GPOS_ERR_ALREADY_USED) {
|
|
GPDEBUG(" Timer is already used... kill timer");
|
|
GpTimerKill(GP32_TIMER_AUDIO_IDX);
|
|
}
|
|
GpTimerSet(GP32_TIMER_AUDIO_IDX);
|
|
|
|
GpPcmInit(gpFreq, gpFormat);
|
|
GpPcmPlay((unsigned short *)buffer, bufferSize, 1);
|
|
GpPcmLock((unsigned short *)buffer, (int *)&idx_buf, (unsigned int *)&soundPos);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void gp_soundBufStop() {
|
|
GpTimerKill(GP32_TIMER_AUDIO_IDX);
|
|
GpPcmStop();
|
|
GpPcmRemove((unsigned short *)buffer);
|
|
free(buffer);
|
|
}
|