mirror of https://github.com/stella-emu/stella.git
implemented gapless playback for WAV files (KidVid)
This commit is contained in:
parent
9d6cee710e
commit
a647b2ba7f
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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};
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue