1 //////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // Nestopia - NES/Famicom emulator written in C++ 4 // 5 // Copyright (C) 2003-2008 Martin Freij 6 // 7 // This file is part of Nestopia. 8 // 9 // Nestopia is free software; you can redistribute it and/or modify 10 // it under the terms of the GNU General Public License as published by 11 // the Free Software Foundation; either version 2 of the License, or 12 // (at your option) any later version. 13 // 14 // Nestopia is distributed in the hope that it will be useful, 15 // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 // GNU General Public License for more details. 18 // 19 // You should have received a copy of the GNU General Public License 20 // along with Nestopia; if not, write to the Free Software 21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 // 23 //////////////////////////////////////////////////////////////////////////////////////// 24 25 #include <new> 26 #include "NstCpu.hpp" 27 #include "NstChips.hpp" 28 #include "NstSoundPlayer.hpp" 29 #include "api/NstApiUser.hpp" 30 31 namespace Nes 32 { 33 namespace Core 34 { 35 namespace Sound 36 { 37 #ifdef NST_MSVC_OPTIMIZE 38 #pragma optimize("s", on) 39 #endif 40 Slot()41 Player::Slot::Slot() 42 : data(NULL) {} 43 ~Slot()44 Player::Slot::~Slot() 45 { 46 delete [] data; 47 } 48 Player(Apu & a,uint n)49 Player::Player(Apu& a,uint n) 50 : Pcm(a), slots(new Slot [n]), numSlots(n) 51 { 52 NST_ASSERT( n ); 53 } 54 ~Player()55 Player::~Player() 56 { 57 delete [] slots; 58 } 59 Create(Apu & apu,const Chips & chips,wcstring const chip,Game game,uint maxSamples)60 Player* Player::Create(Apu& apu,const Chips& chips,wcstring const chip,Game game,uint maxSamples) 61 { 62 if (!maxSamples) 63 return NULL; 64 65 if (chip && chips.Has(chip) && chips[chip].HasSamples()) 66 { 67 game = GAME_UNKNOWN; 68 } 69 else if (game != GAME_UNKNOWN) 70 { 71 maxSamples = uint(game) >> GAME_NUM_SAMPLES_SHIFT; 72 NST_ASSERT( maxSamples ); 73 } 74 else 75 { 76 return NULL; 77 } 78 79 if (Player* const player = new (std::nothrow) Player(apu,maxSamples)) 80 { 81 for (uint i=0; i < maxSamples; ++i) 82 { 83 class Loader : public Api::User::File 84 { 85 const Action action; 86 Slot& slot; 87 const uint id; 88 wcstring const filename; 89 90 Action GetAction() const throw() 91 { 92 return action; 93 } 94 95 wcstring GetName() const throw() 96 { 97 return filename; 98 } 99 100 uint GetId() const throw() 101 { 102 return id; 103 } 104 105 Result SetSampleContent(const void* data,ulong length,bool stereo,uint bits,ulong rate) throw() 106 { 107 if (!data || !length) 108 return RESULT_ERR_INVALID_PARAM; 109 110 if (!Pcm::CanDo( bits, rate )) 111 return RESULT_ERR_UNSUPPORTED; 112 113 iword* NST_RESTRICT dst = new (std::nothrow) iword [length]; 114 115 if (!dst) 116 return RESULT_ERR_OUT_OF_MEMORY; 117 118 slot.data = dst; 119 slot.length = length; 120 slot.rate = rate; 121 122 if (bits == 8) 123 { 124 const byte* NST_RESTRICT src = static_cast<const byte*>(data); 125 const byte* const end = src + length; 126 127 if (stereo) 128 { 129 for (; src != end; src += 2) 130 { 131 const idword sample = (idword(uint(src[0]) << 8) - 32768) + (idword(uint(src[1]) << 8) - 32768); 132 *dst++ = Clamp<Apu::Channel::OUTPUT_MIN,Apu::Channel::OUTPUT_MAX>(sample); 133 } 134 } 135 else 136 { 137 for (; src != end; src += 1) 138 { 139 const idword sample = idword(uint(*src) << 8) - 32768; 140 *dst++ = Clamp<Apu::Channel::OUTPUT_MIN,Apu::Channel::OUTPUT_MAX>(sample); 141 } 142 } 143 } 144 else 145 { 146 const iword* NST_RESTRICT src = static_cast<const iword*>(data); 147 const iword* const end = src + length; 148 149 if (stereo) 150 { 151 for (; src != end; src += 2) 152 { 153 const idword sample = src[0] + src[1]; 154 *dst++ = Clamp<Apu::Channel::OUTPUT_MIN,Apu::Channel::OUTPUT_MAX>(sample); 155 } 156 } 157 else 158 { 159 for (; src != end; src += 1) 160 { 161 const idword sample = *src; 162 *dst++ = Clamp<Apu::Channel::OUTPUT_MIN,Apu::Channel::OUTPUT_MAX>(sample); 163 } 164 } 165 } 166 167 return RESULT_OK; 168 } 169 170 public: 171 172 Loader(Game g,Slot& s,uint i,wcstring f) 173 : 174 action 175 ( 176 g == GAME_MOERO_PRO_YAKYUU ? LOAD_SAMPLE_MOERO_PRO_YAKYUU : 177 g == GAME_MOERO_PRO_YAKYUU_88 ? LOAD_SAMPLE_MOERO_PRO_YAKYUU_88 : 178 g == GAME_MOERO_PRO_TENNIS ? LOAD_SAMPLE_MOERO_PRO_TENNIS : 179 g == GAME_TERAO_NO_DOSUKOI_OOZUMOU ? LOAD_SAMPLE_TERAO_NO_DOSUKOI_OOZUMOU : 180 g == GAME_AEROBICS_STUDIO ? LOAD_SAMPLE_AEROBICS_STUDIO : 181 LOAD_SAMPLE 182 ), 183 slot (s), 184 id (i), 185 filename (f) 186 { 187 } 188 }; 189 190 wcstring filename = L""; 191 192 if (game != GAME_UNKNOWN || *(filename = *chips[chip].Sample(i))) 193 { 194 Loader loader( game, player->slots[i], i, filename ); 195 196 try 197 { 198 Api::User::fileIoCallback( loader ); 199 } 200 catch (...) 201 { 202 delete player; 203 throw; 204 } 205 } 206 } 207 208 for (uint i=0; i < maxSamples; ++i) 209 { 210 if (player->slots[i].data) 211 return player; 212 } 213 214 delete player; 215 } 216 217 return NULL; 218 } 219 Destroy(Player * player)220 void Player::Destroy(Player* player) 221 { 222 delete player; 223 } 224 225 #ifdef NST_MSVC_OPTIMIZE 226 #pragma optimize("", on) 227 #endif 228 } 229 } 230 } 231