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 // Load WAV file
auto* result = SDL_LoadWAV(fileName.c_str(), &myWavSpec, &myWavBuffer, &wavLength); if(fileName != myWavFilename || myWavBuffer == nullptr)
if(result == nullptr || position > wavLength) {
if(myWavBuffer)
{
SDL_FreeWAV(myWavBuffer);
myWavBuffer = nullptr;
}
if(SDL_LoadWAV(fileName.c_str(), &myWavSpec, &myWavBuffer, &myWavLength) == nullptr)
return false; return false;
length = length
? std::min(length, wavLength - position)
: wavLength;
// Set the callback function // Set the callback function
myWavSpec.callback = wavCallback; myWavSpec.callback = wavCallback;
myWavSpec.userdata = nullptr; myWavSpec.userdata = nullptr;
}
if(position > myWavLength)
return false;
myWavFilename = fileName;
myWavLen = length
? std::min(length, myWavLength - position)
: myWavLength;
myWavPos = myWavBuffer + position; myWavPos = myWavBuffer + position;
myWavLen = length;
// Open audio device // Open audio device
if(!myWavDevice)
{
const char* device = myDeviceId ? myDevices.at(myDeviceId).first.c_str() : nullptr; const char* device = myDeviceId ? myDevices.at(myDeviceId).first.c_str() : nullptr;
myWavDevice = SDL_OpenAudioDevice(device, 0, &myWavSpec, nullptr, 0); myWavDevice = SDL_OpenAudioDevice(device, 0, &myWavSpec, nullptr, 0);
if(!myWavDevice) if(!myWavDevice)
return false; return false;
// Play audio // Play audio
SDL_PauseAudioDevice(myWavDevice, 0); SDL_PauseAudioDevice(myWavDevice, 0);
}
return true; return true;
} }
@ -443,9 +448,10 @@ void SoundSDL2::stopWav()
if(myWavBuffer) if(myWavBuffer)
{ {
// Clean up // Clean up
myWavLen = 0;
SDL_CloseAudioDevice(myWavDevice); SDL_CloseAudioDevice(myWavDevice);
myWavDevice = 0;
SDL_FreeWAV(myWavBuffer); SDL_FreeWAV(myWavBuffer);
myWavBuffer = nullptr; myWavBuffer = nullptr;
} }
} }

View File

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

View File

@ -68,7 +68,7 @@ void KidVid::update()
{ {
// Continue playing song after state load // Continue playing song after state load
const uInt8 temp = ourSongPositions[mySongPointer - 1] & 0x7f; 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 // Play the remaining WAV file
const string& fileName = myOSystem.baseDir().getPath() + ((temp < 10) ? "KVSHARED.WAV" : getFileName()); 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); 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 // increase to next bit
++myIdx; ++myIdx;
--myBlockIdx; --myBlockIdx;
@ -172,7 +176,7 @@ void KidVid::update()
if(mySongPlaying) if(mySongPlaying)
{ {
mySongLength = myOSystem.sound().wavSize(); mySongLength = myOSystem.sound().wavSize();
myTapeBusy = (mySongLength > 262 * ClickFrames) || !myBeep; myTapeBusy = (mySongLength > 262 * TapeFrames) || !myBeep;
// Check for end of played sample // Check for end of played sample
if(mySongLength == 0) if(mySongLength == 0)
{ {
@ -188,7 +192,7 @@ void KidVid::update()
if(mySongLength) if(mySongLength)
{ {
--mySongLength; --mySongLength;
myTapeBusy = (mySongLength > ClickFrames); myTapeBusy = (mySongLength > TapeFrames);
} }
} }
} }
@ -259,6 +263,7 @@ void KidVid::openSampleFiles()
44 + 38 + 42 + 62 44 + 38 + 42 + 62
}; };
#ifdef SOUND_SUPPORT
if(!myFilesFound) if(!myFilesFound)
{ {
int i = myGame == Game::Smurfs ? myTape - 1 : myTape + 2; int i = myGame == Game::Smurfs ? myTape - 1 : myTape + 2;
@ -274,6 +279,7 @@ void KidVid::openSampleFiles()
<< "found file: " << "KVSHARED.WAV" << endl; << "found file: " << "KVSHARED.WAV" << endl;
#endif #endif
#endif
mySongLength = 0; mySongLength = 0;
mySongPointer = firstSongPointer[i]; mySongPointer = firstSongPointer[i];
} }
@ -288,7 +294,7 @@ void KidVid::setNextSong()
myBeep = (ourSongPositions[mySongPointer] & 0x80) == 0; myBeep = (ourSongPositions[mySongPointer] & 0x80) == 0;
const uInt8 temp = ourSongPositions[mySongPointer] & 0x7f; const uInt8 temp = ourSongPositions[mySongPointer] & 0x7f;
mySongLength = ourSongStart[temp + 1] - ourSongStart[temp]; mySongLength = ourSongStart[temp + 1] - ourSongStart[temp] - (262 * ClickFrames);
// Play the WAV file // Play the WAV file
const string& fileName = (temp < 10) ? "KVSHARED.WAV" : getFileName(); const string& fileName = (temp < 10) ? "KVSHARED.WAV" : getFileName();
@ -309,7 +315,7 @@ void KidVid::setNextSong()
{ {
myBeep = true; myBeep = true;
myTapeBusy = 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, 3059116,
/* kvs1 */ /* kvs1 */
44, /* Harmony into 1 */ 44, /* Harmony intro 1 */
164685, /* falling notes (into 2) */ 164685, /* falling notes (intro 2) */
395182, /* instructions */ 395182, /* instructions */
750335, /* high notes are high */ 750335, /* high notes are high */
962016, /* my hat's off to you */ 962016, /* my hat's off to you */
1204273, /* 1 2 3 do re mi */ 1204273, /* 1 2 3 do re mi */
1538258, /* Harmony */ 1538258, /* Harmony */
1801683, /* concratulations (all of the Smurfs voted) */ 1801683, /* congratulations (all of the Smurfs voted) */
2086276, /* line or space */ 2086276, /* line or space */
2399093, /* hooray */ 2399093, /* hooray */
2589606, /* hear yeeh */ 2589606, /* hear yeeh */

View File

@ -111,7 +111,8 @@ class KidVid : public Controller
NumBlockBits = NumBlocks * 8, // number of bits / block NumBlockBits = NumBlocks * 8, // number of bits / block
SongPosSize = 44 + 38 + 42 + 62 + 80 + 62, SongPosSize = 44 + 38 + 42 + 62 + 80 + 62,
SongStartSize = 104, 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 // 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 @return True, if the WAV file can be played
*/ */
virtual bool playWav(const string& fileName, uInt32 position = 0, virtual bool playWav(const string& fileName, const uInt32 position = 0,
uInt32 length = 0) { return false; } const uInt32 length = 0) { return false; }
/** /**
Stop any currently playing WAV file. Stop any currently playing WAV file.