6d1f51397e
Still needs sound. Note: won't run with optimizations so release build is -O0
433 lines
13 KiB
C++
Executable File
433 lines
13 KiB
C++
Executable File
// ----------------------------------------------------------------------------
|
|
// ___ ___ ___ ___ ___ ____ ___ _ _
|
|
// /__/ /__/ / / /__ /__/ /__ / /_ / |/ /
|
|
// / / \ /__/ ___/ ___/ ___/ / /__ / / emulator
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
// Copyright 2005 Greg Stanton
|
|
//
|
|
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
// ----------------------------------------------------------------------------
|
|
// Sound.cpp
|
|
// ----------------------------------------------------------------------------
|
|
#include "Sound.h"
|
|
#define SOUND_LATENCY_SCALE 4
|
|
|
|
byte sound_latency = SOUND_LATENCY_VERY_LOW;
|
|
|
|
static const WAVEFORMATEX SOUND_DEFAULT_FORMAT = {WAVE_FORMAT_PCM, 1, 44100, 44100, 1, 8, 0};
|
|
static LPDIRECTSOUND sound_dsound = NULL;
|
|
static LPDIRECTSOUNDBUFFER sound_primaryBuffer = NULL;
|
|
static LPDIRECTSOUNDBUFFER sound_buffer = NULL;
|
|
static WAVEFORMATEX sound_format = SOUND_DEFAULT_FORMAT;
|
|
static uint sound_counter = 0;
|
|
static bool sound_muted = false;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// GetSampleLength
|
|
// ----------------------------------------------------------------------------
|
|
static uint sound_GetSampleLength(uint length, uint unit, uint unitMax) {
|
|
uint sampleLength = length / unitMax;
|
|
uint sampleRemain = length % unitMax;
|
|
if(sampleRemain != 0 && sampleRemain >= unit) {
|
|
sampleLength++;
|
|
}
|
|
return sampleLength;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Resample
|
|
// ----------------------------------------------------------------------------
|
|
static void sound_Resample(const byte* source, byte* target, int length) {
|
|
int measurement = sound_format.nSamplesPerSec;
|
|
int sourceIndex = 0;
|
|
int targetIndex = 0;
|
|
|
|
while(targetIndex < length) {
|
|
if(measurement >= 31440) {
|
|
target[targetIndex++] = source[sourceIndex];
|
|
measurement -= 31440;
|
|
}
|
|
else {
|
|
sourceIndex++;
|
|
measurement += sound_format.nSamplesPerSec;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// RestoreBuffer
|
|
// ----------------------------------------------------------------------------
|
|
static bool sound_RestoreBuffer( ) {
|
|
if(sound_buffer != NULL) {
|
|
HRESULT hr = sound_buffer->Restore( );
|
|
if(FAILED(hr)) {
|
|
logger_LogError(IDS_SOUND1,"");
|
|
logger_LogError("",common_Format(hr));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// ReleaseBuffer
|
|
// ----------------------------------------------------------------------------
|
|
static bool sound_ReleaseBuffer(LPDIRECTSOUNDBUFFER buffer) {
|
|
if(buffer != NULL) {
|
|
HRESULT hr = buffer->Release( );
|
|
sound_buffer = NULL;
|
|
if(FAILED(hr)) {
|
|
logger_LogError(IDS_SOUND2,"");
|
|
logger_LogError("",common_Format(hr));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// ReleaseSound
|
|
// ----------------------------------------------------------------------------
|
|
static bool sound_ReleaseSound( ) {
|
|
if(sound_dsound != NULL) {
|
|
HRESULT hr = sound_dsound->Release( );
|
|
sound_dsound = NULL;
|
|
if(FAILED(hr)) {
|
|
logger_LogError(IDS_SOUND3,"");
|
|
logger_LogError("",common_Format(hr));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Initialize
|
|
// ----------------------------------------------------------------------------
|
|
bool sound_Initialize(HWND hWnd) {
|
|
if(hWnd == NULL) {
|
|
logger_LogError(IDS_INPUT1,"");
|
|
return false;
|
|
}
|
|
|
|
HRESULT hr = DirectSoundCreate(NULL, &sound_dsound, NULL);
|
|
if(FAILED(hr) || sound_dsound == NULL) {
|
|
logger_LogError(IDS_SOUND4,"");
|
|
logger_LogError("",common_Format(hr));
|
|
return false;
|
|
}
|
|
|
|
hr = sound_dsound->SetCooperativeLevel(hWnd, DSSCL_PRIORITY);
|
|
if(FAILED(hr)) {
|
|
logger_LogError(IDS_INPUT6,"");
|
|
logger_LogError("",common_Format(hr));
|
|
return false;
|
|
}
|
|
|
|
DSBUFFERDESC primaryDesc;
|
|
primaryDesc.dwReserved = 0;
|
|
primaryDesc.dwSize = sizeof(DSBUFFERDESC);
|
|
primaryDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
|
|
primaryDesc.dwBufferBytes = 0;
|
|
primaryDesc.lpwfxFormat = NULL;
|
|
|
|
hr = sound_dsound->CreateSoundBuffer(&primaryDesc, &sound_primaryBuffer, NULL);
|
|
if(FAILED(hr) || sound_primaryBuffer == NULL) {
|
|
logger_LogError(IDS_SOUND5,"");
|
|
logger_LogError("",common_Format(hr));
|
|
return false;
|
|
}
|
|
|
|
if(!sound_SetFormat(SOUND_DEFAULT_FORMAT)) {
|
|
logger_LogError(IDS_SOUND6,"");
|
|
return false;
|
|
}
|
|
|
|
//Leonis
|
|
sound_SetSampleRate(samplerate);
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// SetFormat
|
|
// ----------------------------------------------------------------------------
|
|
bool sound_SetFormat(WAVEFORMATEX format) {
|
|
if(sound_dsound == NULL) {
|
|
logger_LogError(IDS_SOUND7,"");
|
|
return false;
|
|
}
|
|
if(sound_primaryBuffer == NULL) {
|
|
logger_LogError(IDS_SOUND8,"");
|
|
return false;
|
|
}
|
|
|
|
HRESULT hr = sound_primaryBuffer->SetFormat(&format);
|
|
if(FAILED(hr)) {
|
|
logger_LogError(IDS_SOUND9,"");
|
|
logger_LogError("",common_Format(hr));
|
|
return false;
|
|
}
|
|
|
|
DSBUFFERDESC secondaryDesc;
|
|
secondaryDesc.dwReserved = 0;
|
|
secondaryDesc.dwSize = sizeof(DSBUFFERDESC);
|
|
secondaryDesc.dwFlags = DSBCAPS_GLOBALFOCUS;
|
|
secondaryDesc.dwBufferBytes = format.nSamplesPerSec;
|
|
secondaryDesc.lpwfxFormat = &format;
|
|
|
|
hr = sound_dsound->CreateSoundBuffer(&secondaryDesc, &sound_buffer, NULL);
|
|
if(FAILED(hr) || sound_buffer == NULL) {
|
|
logger_LogError(IDS_SOUND10,"");
|
|
logger_LogError("",common_Format(hr));
|
|
return false;
|
|
}
|
|
|
|
sound_format = format;
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Store
|
|
// ----------------------------------------------------------------------------
|
|
bool sound_Store( ) {
|
|
if(sound_dsound == NULL) {
|
|
logger_LogError(IDS_SOUND7,"");
|
|
return false;
|
|
}
|
|
if(sound_primaryBuffer == NULL) {
|
|
logger_LogError(IDS_SOUND8,"");
|
|
return false;
|
|
}
|
|
if(sound_buffer == NULL) {
|
|
logger_LogError(IDS_SOUND11,"");
|
|
return false;
|
|
}
|
|
|
|
byte sample[1920];
|
|
uint length = sound_GetSampleLength(sound_format.nSamplesPerSec, prosystem_frame, prosystem_frequency);
|
|
sound_Resample(tia_buffer, sample, length);
|
|
|
|
if(cartridge_pokey) {
|
|
byte pokeySample[1920];
|
|
sound_Resample(pokey_buffer, pokeySample, length);
|
|
for(int index = 0; index < length; index++) {
|
|
sample[index] += pokeySample[index];
|
|
sample[index] = sample[index] / 2;
|
|
}
|
|
}
|
|
|
|
DWORD lockCount = 0;
|
|
byte* lockStream = NULL;
|
|
DWORD wrapCount = 0;
|
|
byte* wrapStream = NULL;
|
|
|
|
HRESULT hr = sound_buffer->Lock(sound_counter, length, (void**)&lockStream, &lockCount, (void**)&wrapStream, &wrapCount, 0);
|
|
if(FAILED(hr) || lockStream == NULL) {
|
|
logger_LogError(IDS_SOUND12,"");
|
|
logger_LogError("",common_Format(hr));
|
|
if(hr != DSERR_BUFFERLOST || !sound_RestoreBuffer( )) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
uint bufferCounter = 0;
|
|
for(uint lockIndex = 0; lockIndex < lockCount; lockIndex++) {
|
|
lockStream[lockIndex] = sample[bufferCounter++];
|
|
}
|
|
|
|
for(uint wrapIndex = 0; wrapIndex < wrapCount; wrapIndex++) {
|
|
wrapStream[wrapIndex] = sample[bufferCounter++];
|
|
}
|
|
|
|
hr = sound_buffer->Unlock(lockStream, lockCount, wrapStream, wrapCount);
|
|
if(FAILED(hr)) {
|
|
logger_LogError(IDS_SOUND13,"");
|
|
logger_LogError("",common_Format(hr));
|
|
if(hr != DSERR_BUFFERLOST || !sound_RestoreBuffer( )) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
sound_counter += length;
|
|
if(sound_counter >= sound_format.nSamplesPerSec) {
|
|
sound_counter -= sound_format.nSamplesPerSec;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Clear
|
|
// ----------------------------------------------------------------------------
|
|
bool sound_Clear( ) {
|
|
if(sound_dsound == NULL) {
|
|
logger_LogError(IDS_SOUND7,"");
|
|
return false;
|
|
}
|
|
if(sound_primaryBuffer == NULL) {
|
|
logger_LogError(IDS_SOUND8,"");
|
|
return false;
|
|
}
|
|
if(sound_buffer == NULL) {
|
|
logger_LogError(IDS_SOUND11,"");
|
|
return false;
|
|
}
|
|
|
|
byte* lockStream = NULL;
|
|
DWORD lockCount = 0;
|
|
HRESULT hr = sound_buffer->Lock(0, sound_format.nSamplesPerSec, (void**)&lockStream, &lockCount, NULL, NULL, DSBLOCK_ENTIREBUFFER);
|
|
if(FAILED(hr) || lockStream == NULL) {
|
|
logger_LogError(IDS_SOUND12,"");
|
|
logger_LogError("",common_Format(hr));
|
|
if(hr != DSERR_BUFFERLOST || !sound_RestoreBuffer( )) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for(uint lockIndex = 0; lockIndex < lockCount; lockIndex++) {
|
|
lockStream[lockIndex] = 0;
|
|
}
|
|
|
|
hr = sound_buffer->Unlock(lockStream, lockCount, NULL, NULL);
|
|
if(FAILED(hr)) {
|
|
logger_LogError(IDS_SOUND13,"");
|
|
logger_LogError("",common_Format(hr));
|
|
if(hr != DSERR_BUFFERLOST || !sound_RestoreBuffer( )) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Play
|
|
// ----------------------------------------------------------------------------
|
|
bool sound_Play( ) {
|
|
if(sound_dsound == NULL) {
|
|
logger_LogError(IDS_SOUND7,"");
|
|
return false;
|
|
}
|
|
if(sound_primaryBuffer == NULL) {
|
|
logger_LogError(IDS_SOUND8,"");
|
|
return false;
|
|
}
|
|
if(sound_buffer == NULL) {
|
|
logger_LogError(IDS_SOUND11,"");
|
|
return false;
|
|
}
|
|
|
|
if(!sound_muted) {
|
|
HRESULT hr = sound_buffer->SetCurrentPosition(0);
|
|
if(FAILED(hr)) {
|
|
logger_LogError(IDS_SOUND14,"");
|
|
logger_LogError("",common_Format(hr));
|
|
return false;
|
|
}
|
|
|
|
hr = sound_buffer->Play(0, 0, DSBPLAY_LOOPING);
|
|
if(FAILED(hr)) {
|
|
logger_LogError(IDS_SOUND15,"");
|
|
logger_LogError("",common_Format(hr));
|
|
if(hr != DSERR_BUFFERLOST || !sound_RestoreBuffer( )) {
|
|
return false;
|
|
}
|
|
}
|
|
sound_counter = (sound_format.nSamplesPerSec / prosystem_frequency) * (sound_latency * SOUND_LATENCY_SCALE);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Stop
|
|
// ----------------------------------------------------------------------------
|
|
bool sound_Stop( ) {
|
|
if(sound_dsound == NULL) {
|
|
logger_LogError(IDS_SOUND7,"");
|
|
return false;
|
|
}
|
|
if(sound_primaryBuffer == NULL) {
|
|
logger_LogError(IDS_SOUND8,"");
|
|
return false;
|
|
}
|
|
if(sound_buffer == NULL) {
|
|
logger_LogError(IDS_SOUND11,"");
|
|
return false;
|
|
}
|
|
|
|
HRESULT hr = sound_buffer->Stop( );
|
|
if(FAILED(hr)) {
|
|
logger_LogError(IDS_SOUND16,"");
|
|
logger_LogError("",common_Format(hr));
|
|
if(hr != DSERR_BUFFERLOST || !sound_RestoreBuffer( )) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// SetSampleRate
|
|
// ----------------------------------------------------------------------------
|
|
bool sound_SetSampleRate(uint rate) {
|
|
sound_format.nSamplesPerSec = rate;
|
|
sound_format.nAvgBytesPerSec = rate;
|
|
return sound_SetFormat(sound_format);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// GetSampleRate
|
|
// ----------------------------------------------------------------------------
|
|
uint sound_GetSampleRate( ) {
|
|
return sound_format.nSamplesPerSec;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// SetMuted
|
|
// ----------------------------------------------------------------------------
|
|
bool sound_SetMuted(bool muted) {
|
|
if(sound_muted != muted) {
|
|
if(!muted) {
|
|
if(!sound_Play( )) {
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
if(!sound_Stop( )) {
|
|
return false;
|
|
}
|
|
}
|
|
sound_muted = muted;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// IsMuted
|
|
// ----------------------------------------------------------------------------
|
|
bool sound_IsMuted( ) {
|
|
return sound_muted;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Release
|
|
// ----------------------------------------------------------------------------
|
|
void sound_Release( ) {
|
|
sound_ReleaseBuffer(sound_buffer);
|
|
sound_ReleaseBuffer(sound_primaryBuffer);
|
|
sound_ReleaseSound( );
|
|
} |