added WAV playing and adapted KidVid code accordingly

This commit is contained in:
Thomas Jentzsch 2022-09-03 16:54:33 +02:00
parent 162921b9f3
commit ba6b32aa21
6 changed files with 200 additions and 136 deletions

View File

@ -72,6 +72,10 @@ SoundSDL2::~SoundSDL2()
{
ASSERT_MAIN_THREAD;
stopWav();
if(myWavDevice)
SDL_CloseAudioDevice(myWavDevice);
if (!myIsInitializedFlag) return;
SDL_CloseAudioDevice(myDevice);
@ -194,6 +198,7 @@ void SoundSDL2::open(shared_ptr<AudioQueue> audioQueue,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL2::close()
{
stopWav();
if(!myIsInitializedFlag) return;
mute(true);
@ -209,6 +214,8 @@ bool SoundSDL2::mute(bool state)
const bool oldstate = SDL_GetAudioDeviceStatus(myDevice) == SDL_AUDIO_PAUSED;
if(myIsInitializedFlag)
SDL_PauseAudioDevice(myDevice, state ? 1 : 0);
if(myWavDevice)
SDL_PauseAudioDevice(myWavDevice, state ? 1 : 0);
return oldstate;
}
@ -395,4 +402,57 @@ void SoundSDL2::callback(void* udata, uInt8* stream, int len)
SDL_memset(stream, 0, len);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SoundSDL2::playWav(const char* fileName, uInt32 position, uInt32 length)
{
// ToDos:
// - volume (requires callback using SDL_MixAudio)
// - (un)mute
SDL_AudioSpec wavSpec;
uInt32 wavLength;
// Stop any playing WAVs
stopWav();
// Load WAV file
SDL_AudioSpec* result = SDL_LoadWAV(fileName, &wavSpec, &myWavBuffer, &wavLength);
if(result == NULL || position > wavLength)
return false;
length = length
? std::min(length, wavLength - position)
: wavLength;
// Open audio device
const char* device = myDeviceId ? myDevices.at(myDeviceId).first.c_str() : nullptr;
myWavDevice = SDL_OpenAudioDevice(device, 0, &wavSpec, NULL, 0);
if(!myWavDevice)
return false;
// Play audio
int success = SDL_QueueAudio(myWavDevice, myWavBuffer + position, length);
SDL_PauseAudioDevice(myWavDevice, 0);
return success == 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL2::stopWav()
{
if(myWavBuffer)
{
// Clean up
SDL_CloseAudioDevice(myWavDevice);
SDL_FreeWAV(myWavBuffer);
myWavBuffer = nullptr;
}
}
uInt32 SoundSDL2::wavSize() const
{
return myWavBuffer ? SDL_GetQueuedAudioSize(myWavDevice) : 0;
}
#endif // SOUND_SUPPORT

View File

@ -107,6 +107,29 @@ class SoundSDL2 : public Sound
*/
string about() const override;
/**
Play a WAV file.
@param fileName The name of the WAV file
@param position The position to start playing
@param length The played length
@return True, if the WAV file can be played
*/
bool playWav(const char* fileName, uInt32 position = 0, uInt32 length = 0) override;
/**
Stop any currently playing WAV file.
*/
void stopWav() override;
/**
Get the size of the WAV file which remains to be played.
@return The remaining number of bytes
*/
uInt32 wavSize() const override;
protected:
/**
This method is called to query the audio devices.
@ -161,6 +184,9 @@ class SoundSDL2 : public Sound
AudioSettings& myAudioSettings;
SDL_AudioDeviceID myWavDevice{0};
uInt8* myWavBuffer{nullptr};
string myAboutString;
private:

View File

@ -1028,7 +1028,8 @@ unique_ptr<Controller> Console::getControllerPort(const Controller::Type type,
break;
case Controller::Type::KidVid:
controller = make_unique<KidVid>(port, myEvent, *mySystem, myOSystem.baseDir().getPath(), romMd5);
controller = make_unique<KidVid>(port, myEvent, *mySystem, myOSystem.baseDir().getPath(),
myOSystem.sound(), romMd5);
break;
case Controller::Type::MindLink:

View File

@ -16,14 +16,16 @@
//============================================================================
#include "Event.hxx"
#include "Sound.hxx"
#include "KidVid.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KidVid::KidVid(Jack jack, const Event& event, const System& system,
const string& baseDir, const string& romMd5)
const string& baseDir, Sound& sound, const string& romMd5)
: Controller(jack, event, system, Controller::Type::KidVid),
myEnabled{myJack == Jack::Right},
myBaseDir{baseDir}
myBaseDir{baseDir},
mySound{sound}
{
// Right now, there are only two games that use the KidVid
if(romMd5 == "ee6665683ebdb539e89ba620981cb0f6")
@ -59,7 +61,8 @@ void KidVid::update()
if(myEvent.get(Event::ConsoleReset))
{
myTape = 0; // rewind Kid Vid tape
closeSampleFiles();
myFilesFound = mySongPlaying = false;
mySound.stopWav();
}
if(!myTape)
{
@ -71,9 +74,8 @@ void KidVid::update()
myTape = myGame == BBears ? 4 : 1; // Berenstain Bears or Smurfs Save The Day?
if(myTape)
{
//cerr << "myTape = " << myTape << endl;0
myIdx = myGame == BBears ? BlockBits : 0;
myBlockIdx = BlockBits;
myIdx = myGame == BBears ? NumBlockBits : 0;
myBlockIdx = NumBlockBits;
myBlock = 0;
openSampleFiles();
}
@ -92,49 +94,58 @@ void KidVid::update()
if(!myBlockIdx)
{
if(!myBlock)
myIdx = ((myTape * 6) + 12 - Blocks) * 8; //KVData00-KVData=12
myIdx = ((myTape * 6) + 12 - NumBlocks) * 8; //KVData00-KVData=12
else
{
if(myGame == Smurfs)
{
if(myBlock >= ourBlocks[myTape - 1])
myIdx = 42 * 8; //KVData80-KVData=42
else
{
myIdx = 36 * 8;//KVPause-KVData=36
setNextSong();
}
}
const uInt32 lastBlock = myGame == Smurfs
? ourBlocks[myTape - 1]
: ourBlocks[myTape + 2 - 1];
if(myBlock >= lastBlock)
myIdx = 42 * 8; //KVData80-KVData=42
else
{
if(myBlock >= ourBlocks[myTape + 2 - 1])
myIdx = 42 * 8; //KVData80-KVData=42
else
{
myIdx = 36 * 8;//KVPause-KVData=36
setNextSong();
}
myIdx = 36 * 8;//KVPause-KVData=36
setNextSong();
}
}
++myBlock;
myBlockIdx = BlockBits;
myBlockIdx = NumBlockBits;
}
}
if(myFilesFound)
{
if(mySongPlaying)
{
myTapeBusy = (mySound.wavSize() > 262 * 48) || !myBeep;
// Check for end of played sample
if(mySound.wavSize() == 0)
{
mySongPlaying = false;
myTapeBusy = !myBeep;
if(!myBeep)
setNextSong();
}
}
}
else
{
if(mySongLength)
{
--mySongLength;
myTapeBusy = (mySongLength > 48);
}
}
// emulate playing the songs (but MUCH faster!)
// TODO: this has to be done by an Audio class
for(int i = mySongCounter / 8; i >= 0; --i)
getNextSampleByte();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KidVid::openSampleFiles()
{
#ifdef KID_TAPE
static constexpr const char* fileNames[6] = {
"KVS3.WAV", "KVS1.WAV", "KVS2.WAV",
"KVB3.WAV", "KVB1.WAV", "KVB2.WAV"
};
static constexpr uInt32 startSong[6] = {
static constexpr uInt32 firstSongPointer[6] = {
44 + 38,
0,
44,
@ -143,114 +154,62 @@ void KidVid::openSampleFiles()
44 + 38 + 42 + 62
};
if(!myFilesOpened)
if(!myFilesFound)
{
int i = myGame == Smurfs ? myTape - 1 : myTape + 2;
if(myTape == 4) i = 3;
mySampleFile.open(myBaseDir + fileNames[i], std::ios::binary);
if(mySampleFile.is_open())
{
cerr << "opened file: " << fileNames[i] << endl;
mySharedSampleFile.open(myBaseDir + "KVSHARED.WAV", std::ios::binary);
if(!mySharedSampleFile.is_open())
mySampleFile.close();
else
{
cerr << "opened file: " << "kvshared.wav" << endl;
mySampleFile.seekg(45);
myFilesOpened = true;
}
}
mySongCounter = 0;
myFilePointer = startSong[i];
mySampleFile = myBaseDir + fileNames[i];
std::ifstream f1, f2;
f1.open(mySampleFile, std::ios::binary);
f2.open(myBaseDir + "KVSHARED.WAV", std::ios::binary);
myFilesFound = f1.is_open() && f2.is_open();
if(myFilesFound)
cerr << "found file: " << fileNames[i] << endl
<< "found file: " << "KVSHARED.WAV" << endl;
mySongLength = 0;
mySongPointer = firstSongPointer[i];
}
#endif
myTapeBusy = false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KidVid::closeSampleFiles()
{
#ifdef KID_TAPE
if(mySampleFile.is_open())
mySampleFile.close();
if(mySharedSampleFile.is_open())
mySharedSampleFile.close();
myFilesOpened = false;
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KidVid::setNextSong()
{
#ifdef KID_TAPE
if(myFilesOpened)
if(myFilesFound)
{
//cerr << endl << std::dec << mySongCounter << ", " << myFilePointer << endl;
myBeep = (ourSongPositions[myFilePointer] & 0x80) == 0;
myBeep = (ourSongPositions[mySongPointer] & 0x80) == 0;
const uInt8 temp = ourSongPositions[myFilePointer] & 0x7f;
mySharedData = (temp < 10);
mySongCounter = ourSongStart[temp+1] - ourSongStart[temp];
const uInt8 temp = ourSongPositions[mySongPointer] & 0x7f;
mySongLength = ourSongStart[temp+1] - ourSongStart[temp];
if(mySharedData)
mySharedSampleFile.seekg(ourSongStart[temp]);
else
mySampleFile.seekg(ourSongStart[temp]);
// Play the WAV file
const string fileName = (temp < 10) ? myBaseDir + "KVSHARED.WAV" : mySampleFile;
mySound.playWav(fileName.c_str(), ourSongStart[temp], mySongLength);
++myFilePointer;
myTapeBusy = true;
mySongPlaying = myTapeBusy = true;
++mySongPointer;
}
else
#endif
{
myBeep = true;
myTapeBusy = true;
mySongCounter = 10 * 80*262; /* delay needed for Harmony without tape */
mySongLength = 80; /* delay needed for Harmony without tape */
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KidVid::getNextSampleByte()
{
static bool oddeven = false;
if(mySongCounter == 0)
{
#ifdef KID_TAPE
mySampleByte = 0x80;
#endif
}
else
{
oddeven = !oddeven;
if(oddeven)
{
mySongCounter--;
myTapeBusy = (mySongCounter > 262 * 48) || !myBeep;
#ifdef KID_TAPE
mySampleByte = myFilesOpened
? (mySharedData ? mySharedSampleFile.get() : mySampleFile.get())
: 0x80;
#endif
if(!myBeep && (mySongCounter == 0))
setNextSong();
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const std::array<uInt8, KidVid::Blocks> KidVid::ourBlocks = {
const std::array<uInt8, KidVid::NumBlocks> KidVid::ourBlocks = {
2+40, 2+21, 2+35, /* Smurfs tapes 3, 1, 2 */
42+60, 42+78, 42+60 /* BBears tapes 1, 2, 3 (40 extra blocks for intro) */
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const std::array<uInt8, KidVid::BlockBits> KidVid::ourData = {
const std::array<uInt8, KidVid::NumBlockBits> KidVid::ourData = {
/* KVData44 */
0x7b, // 0111 1011b ; (1)0
0x1e, // 0001 1110b ; 1
@ -409,7 +368,7 @@ const std::array<uInt32, KidVid::SongStartSize> KidVid::ourSongStart = {
3720920,
/* kvb1 */
44, /* 3 */
44, /* 3 */ // can be one too late!
592749, /* 5 */
936142, /* 2 */
1465343, /* 4 */

View File

@ -18,9 +18,8 @@
#ifndef KIDVID_HXX
#define KIDVID_HXX
//#define KID_TAPE
class Event;
class Sound;
#include "bspf.hxx"
#include "Control.hxx"
@ -48,7 +47,7 @@ class KidVid : public Controller
@param romMd5 The md5 of the ROM using this controller
*/
KidVid(Jack jack, const Event& event, const System& system,
const string& baseDir, const string& romMd5);
const string& baseDir, Sound& sound, const string& romMd5);
~KidVid() override = default;
public:
@ -76,21 +75,16 @@ class KidVid : public Controller
private:
// Open/close a WAV sample file
void openSampleFiles();
void closeSampleFiles();
// Jump to next song in the sequence
void setNextSong();
// Generate next sample byte
// TODO - rework this, perhaps send directly to sound class
void getNextSampleByte();
private:
static constexpr uInt32
Smurfs = 0x44,
BBears = 0x48,
Blocks = 6, // number of bytes / block
BlockBits = Blocks*8, // number of bits / block
Smurfs = 0x44,
BBears = 0x48,
NumBlocks = 6, // number of bytes / block
NumBlockBits = NumBlocks*8, // number of bits / block
SongPosSize = 44+38+42+62+80+62,
SongStartSize = 104
;
@ -100,28 +94,27 @@ class KidVid : public Controller
bool myEnabled{false};
string myBaseDir;
#ifdef KID_TAPE
// The file streams for the WAV files
std::ifstream mySampleFile, mySharedSampleFile;
// Indicates if sample files have been successfully opened
bool myFilesOpened{false};
Sound& mySound;
uInt32 myFilePointer{0};
bool mySharedData{false};
uInt8 mySampleByte{0};
#endif
// Path and name of the current sample file
string mySampleFile;
// Indicates if the sample files have been found
bool myFilesFound{false};
uInt32 mySongPointer{0};
// Is the tape currently 'busy' / in use?
bool myTapeBusy{false};
uInt32 mySongCounter{0};
bool mySongPlaying{false};
uInt32 mySongLength{0};
bool myBeep{false};
uInt32 myGame{0}, myTape{0};
uInt32 myIdx{0}, myBlock{0}, myBlockIdx{0};
// Number of blocks and data on tape
static const std::array<uInt8, Blocks> ourBlocks;
static const std::array<uInt8, BlockBits> ourData;
static const std::array<uInt8, NumBlocks> ourBlocks;
static const std::array<uInt8, NumBlockBits> ourData;
static const std::array<uInt8, SongPosSize> ourSongPositions;
static const std::array<uInt32, SongStartSize> ourSongStart;

View File

@ -23,6 +23,7 @@ class AudioQueue;
class EmulationTiming;
#include "bspf.hxx"
#include "Variant.hxx"
/**
This class is an abstract base class for the various sound objects.
@ -104,6 +105,29 @@ class Sound
*/
const VariantList& supportedDevices() const {return myDevices;}
/**
Play a WAV file.
@param fileName The name of the WAV file
@param position The position to start playing
@param length The played length
@return True, if the WAV file can be played
*/
virtual bool playWav(const char* fileName, uInt32 position = 0, uInt32 length = 0) = 0;
/**
Stop any currently playing WAV file.
*/
virtual void stopWav() = 0;
/**
Get the size of the WAV file which remains to be played.
@return The remaining number of bytes
*/
virtual uInt32 wavSize() const = 0;
protected:
/**
This method is called to query the audio devices.
@ -112,6 +136,7 @@ class Sound
*/
virtual void queryHardware(VariantList& devices) = 0;
protected:
// The OSystem for this sound object
OSystem& myOSystem;