implemented gapless playback for WAV files (KidVid)

This commit is contained in:
Thomas Jentzsch 2022-09-13 15:24:19 +02:00
parent 9d6cee710e
commit a647b2ba7f
5 changed files with 56 additions and 41 deletions

View File

@ -401,39 +401,44 @@ void SoundSDL2::callback(void* udata, uInt8* stream, int len)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SoundSDL2::playWav(const string& fileName, uInt32 position, uInt32 length)
bool SoundSDL2::playWav(const string& fileName, const uInt32 position,
const uInt32 length)
{
uInt32 wavLength{0};
// Stop any playing WAVs
stopWav();
// Load WAV file
auto* result = SDL_LoadWAV(fileName.c_str(), &myWavSpec, &myWavBuffer, &wavLength);
if(result == nullptr || position > wavLength)
if(fileName != myWavFilename || myWavBuffer == nullptr)
{
if(myWavBuffer)
{
SDL_FreeWAV(myWavBuffer);
myWavBuffer = nullptr;
}
if(SDL_LoadWAV(fileName.c_str(), &myWavSpec, &myWavBuffer, &myWavLength) == nullptr)
return false;
// Set the callback function
myWavSpec.callback = wavCallback;
myWavSpec.userdata = nullptr;
}
if(position > myWavLength)
return false;
length = length
? std::min(length, wavLength - position)
: wavLength;
// Set the callback function
myWavSpec.callback = wavCallback;
myWavSpec.userdata = nullptr;
myWavFilename = fileName;
myWavLen = length
? std::min(length, myWavLength - position)
: myWavLength;
myWavPos = myWavBuffer + position;
myWavLen = length;
// Open audio device
const char* device = myDeviceId ? myDevices.at(myDeviceId).first.c_str() : nullptr;
myWavDevice = SDL_OpenAudioDevice(device, 0, &myWavSpec, nullptr, 0);
if(!myWavDevice)
return false;
// Play audio
SDL_PauseAudioDevice(myWavDevice, 0);
{
const char* device = myDeviceId ? myDevices.at(myDeviceId).first.c_str() : nullptr;
myWavDevice = SDL_OpenAudioDevice(device, 0, &myWavSpec, nullptr, 0);
if(!myWavDevice)
return false;
// Play audio
SDL_PauseAudioDevice(myWavDevice, 0);
}
return true;
}
@ -443,9 +448,10 @@ void SoundSDL2::stopWav()
if(myWavBuffer)
{
// Clean up
myWavLen = 0;
SDL_CloseAudioDevice(myWavDevice);
myWavDevice = 0;
SDL_FreeWAV(myWavBuffer);
myWavBuffer = nullptr;
}
}

View File

@ -116,8 +116,8 @@ class SoundSDL2 : public Sound
@return True, if the WAV file can be played
*/
bool playWav(const string& fileName, uInt32 position = 0,
uInt32 length = 0) override;
bool playWav(const string& fileName, const uInt32 position = 0,
const uInt32 length = 0) override;
/**
Stop any currently playing WAV file.
@ -186,6 +186,8 @@ class SoundSDL2 : public Sound
AudioSettings& myAudioSettings;
// WAV file sound variables
string myWavFilename{EmptyString};
uInt32 myWavLength{0};
SDL_AudioDeviceID myWavDevice{0};
uInt8* myWavBuffer{nullptr};

View File

@ -68,7 +68,7 @@ void KidVid::update()
{
// Continue playing song after state load
const uInt8 temp = ourSongPositions[mySongPointer - 1] & 0x7f;
const uInt32 songLength = ourSongStart[temp + 1] - ourSongStart[temp];
const uInt32 songLength = ourSongStart[temp + 1] - ourSongStart[temp] - (262 * ClickFrames);
// Play the remaining WAV file
const string& fileName = myOSystem.baseDir().getPath() + ((temp < 10) ? "KVSHARED.WAV" : getFileName());
@ -140,6 +140,10 @@ void KidVid::update()
{
setPin(DigitalPin::Four, (ourData[myIdx >> 3] << (myIdx & 0x07)) & 0x80);
#ifdef DEBUG_BUILD
cerr << (DigitalPin::Four, (ourData[myIdx >> 3] << (myIdx & 0x07)) & 0x80 ? "X" : ".");
#endif
// increase to next bit
++myIdx;
--myBlockIdx;
@ -172,7 +176,7 @@ void KidVid::update()
if(mySongPlaying)
{
mySongLength = myOSystem.sound().wavSize();
myTapeBusy = (mySongLength > 262 * ClickFrames) || !myBeep;
myTapeBusy = (mySongLength > 262 * TapeFrames) || !myBeep;
// Check for end of played sample
if(mySongLength == 0)
{
@ -188,7 +192,7 @@ void KidVid::update()
if(mySongLength)
{
--mySongLength;
myTapeBusy = (mySongLength > ClickFrames);
myTapeBusy = (mySongLength > TapeFrames);
}
}
}
@ -259,6 +263,7 @@ void KidVid::openSampleFiles()
44 + 38 + 42 + 62
};
#ifdef SOUND_SUPPORT
if(!myFilesFound)
{
int i = myGame == Game::Smurfs ? myTape - 1 : myTape + 2;
@ -267,13 +272,14 @@ void KidVid::openSampleFiles()
myFilesFound = FSNode(myOSystem.baseDir().getPath() + getFileName()).exists() &&
FSNode(myOSystem.baseDir().getPath() + "KVSHARED.WAV").exists();
#ifdef DEBUG_BUILD
#ifdef DEBUG_BUILD
if(myFilesFound)
cerr << endl
<< "found file: " << getFileName() << endl
<< "found file: " << "KVSHARED.WAV" << endl;
#endif
#endif
#endif
mySongLength = 0;
mySongPointer = firstSongPointer[i];
}
@ -288,7 +294,7 @@ void KidVid::setNextSong()
myBeep = (ourSongPositions[mySongPointer] & 0x80) == 0;
const uInt8 temp = ourSongPositions[mySongPointer] & 0x7f;
mySongLength = ourSongStart[temp + 1] - ourSongStart[temp];
mySongLength = ourSongStart[temp + 1] - ourSongStart[temp] - (262 * ClickFrames);
// Play the WAV file
const string& fileName = (temp < 10) ? "KVSHARED.WAV" : getFileName();
@ -298,9 +304,9 @@ void KidVid::setNextSong()
msg << "Read song #" << mySongPointer << " (" << fileName << ")";
myCallback(msg.str(), false);
#ifdef DEBUG_BUILD
#ifdef DEBUG_BUILD
cerr << fileName << ": " << (ourSongPositions[mySongPointer] & 0x7f) << endl;
#endif
#endif
mySongPlaying = myTapeBusy = true;
++mySongPointer;
@ -309,7 +315,7 @@ void KidVid::setNextSong()
{
myBeep = true;
myTapeBusy = true;
mySongLength = 80; /* delay needed for Harmony without tape */
mySongLength = TapeFrames + 32; /* delay needed for Harmony without tape */
}
}
@ -438,14 +444,14 @@ const std::array<uInt32, KidVid::SongStartSize> KidVid::ourSongStart = {
3059116,
/* kvs1 */
44, /* Harmony into 1 */
164685, /* falling notes (into 2) */
44, /* Harmony intro 1 */
164685, /* falling notes (intro 2) */
395182, /* instructions */
750335, /* high notes are high */
962016, /* my hat's off to you */
1204273, /* 1 2 3 do re mi */
1538258, /* Harmony */
1801683, /* concratulations (all of the Smurfs voted) */
1801683, /* congratulations (all of the Smurfs voted) */
2086276, /* line or space */
2399093, /* hooray */
2589606, /* hear yeeh */

View File

@ -111,7 +111,8 @@ class KidVid : public Controller
NumBlockBits = NumBlocks * 8, // number of bits / block
SongPosSize = 44 + 38 + 42 + 62 + 80 + 62,
SongStartSize = 104,
ClickFrames = 48 // eliminate click noise at song end
TapeFrames = 60,
ClickFrames = 3 // eliminate click noise at song end
;
// Whether the KidVid device is enabled (only for games that it

View File

@ -114,8 +114,8 @@ class Sound
@return True, if the WAV file can be played
*/
virtual bool playWav(const string& fileName, uInt32 position = 0,
uInt32 length = 0) { return false; }
virtual bool playWav(const string& fileName, const uInt32 position = 0,
const uInt32 length = 0) { return false; }
/**
Stop any currently playing WAV file.