nestopia/source/core/NstSoundPlayer.cpp
2012-09-02 13:13:55 -04:00

230 lines
5.7 KiB
C++

////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia 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.
//
// Nestopia 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 Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include <new>
#include "NstCpu.hpp"
#include "NstChips.hpp"
#include "NstSoundPlayer.hpp"
#include "api/NstApiUser.hpp"
namespace Nes
{
namespace Core
{
namespace Sound
{
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
Player::Slot::Slot()
: data(NULL) {}
Player::Slot::~Slot()
{
delete [] data;
}
Player::Player(Apu& a,uint n)
: Pcm(a), slots(new Slot [n]), numSlots(n)
{
NST_ASSERT( n );
}
Player::~Player()
{
delete [] slots;
}
Player* Player::Create(Apu& apu,const Chips& chips,wcstring const chip,Game game,uint maxSamples)
{
if (!maxSamples)
return NULL;
if (chip && chips.Has(chip) && chips[chip].HasSamples())
{
game = GAME_UNKNOWN;
}
else if (game != GAME_UNKNOWN)
{
maxSamples = uint(game) >> GAME_NUM_SAMPLES_SHIFT;
NST_ASSERT( maxSamples );
}
else
{
return NULL;
}
if (Player* const player = new (std::nothrow) Player(apu,maxSamples))
{
for (uint i=0; i < maxSamples; ++i)
{
class Loader : public Api::User::File
{
const Action action;
Slot& slot;
const uint id;
wcstring const filename;
Action GetAction() const throw()
{
return action;
}
wcstring GetName() const throw()
{
return filename;
}
uint GetId() const throw()
{
return id;
}
Result SetSampleContent(const void* data,ulong length,bool stereo,uint bits,ulong rate) throw()
{
if (!data || !length)
return RESULT_ERR_INVALID_PARAM;
if (!Pcm::CanDo( bits, rate ))
return RESULT_ERR_UNSUPPORTED;
iword* NST_RESTRICT dst = new (std::nothrow) iword [length];
if (!dst)
return RESULT_ERR_OUT_OF_MEMORY;
slot.data = dst;
slot.length = length;
slot.rate = rate;
if (bits == 8)
{
const byte* NST_RESTRICT src = static_cast<const byte*>(data);
const byte* const end = src + length;
if (stereo)
{
for (; src != end; src += 2)
{
const idword sample = (idword(uint(src[0]) << 8) - 32768) + (idword(uint(src[1]) << 8) - 32768);
*dst++ = Clamp<Apu::Channel::OUTPUT_MIN,Apu::Channel::OUTPUT_MAX>(sample);
}
}
else
{
for (; src != end; src += 1)
{
const idword sample = idword(uint(*src) << 8) - 32768;
*dst++ = Clamp<Apu::Channel::OUTPUT_MIN,Apu::Channel::OUTPUT_MAX>(sample);
}
}
}
else
{
const iword* NST_RESTRICT src = static_cast<const iword*>(data);
const iword* const end = src + length;
if (stereo)
{
for (; src != end; src += 2)
{
const idword sample = src[0] + src[1];
*dst++ = Clamp<Apu::Channel::OUTPUT_MIN,Apu::Channel::OUTPUT_MAX>(sample);
}
}
else
{
for (; src != end; src += 1)
{
const idword sample = *src;
*dst++ = Clamp<Apu::Channel::OUTPUT_MIN,Apu::Channel::OUTPUT_MAX>(sample);
}
}
}
return RESULT_OK;
}
public:
Loader(Game g,Slot& s,uint i,wcstring f)
:
action
(
g == GAME_MOERO_PRO_YAKYUU ? LOAD_SAMPLE_MOERO_PRO_YAKYUU :
g == GAME_MOERO_PRO_YAKYUU_88 ? LOAD_SAMPLE_MOERO_PRO_YAKYUU_88 :
g == GAME_MOERO_PRO_TENNIS ? LOAD_SAMPLE_MOERO_PRO_TENNIS :
g == GAME_TERAO_NO_DOSUKOI_OOZUMOU ? LOAD_SAMPLE_TERAO_NO_DOSUKOI_OOZUMOU :
g == GAME_AEROBICS_STUDIO ? LOAD_SAMPLE_AEROBICS_STUDIO :
LOAD_SAMPLE
),
slot (s),
id (i),
filename (f)
{
}
};
wcstring filename = L"";
if (game != GAME_UNKNOWN || *(filename = *chips[chip].Sample(i)))
{
Loader loader( game, player->slots[i], i, filename );
try
{
Api::User::fileIoCallback( loader );
}
catch (...)
{
delete player;
throw;
}
}
}
for (uint i=0; i < maxSamples; ++i)
{
if (player->slots[i].data)
return player;
}
delete player;
}
return NULL;
}
void Player::Destroy(Player* player)
{
delete player;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
}
}
}