1/*---------------------------------------------------------------------------* 2 Project: NintendoWare 3 File: snd_HardwareChannelAX.cppi 4 5 Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. 6 7 These coded instructions, statements, and computer programs contain 8 proprietary information of Nintendo of America Inc. and/or Nintendo 9 Company Ltd., and are protected by Federal copyright law. They may 10 not be disclosed to third parties or copied or duplicated in any form, 11 in whole or in part, without the prior written consent of Nintendo. 12 13 $Revision:$ 14 *---------------------------------------------------------------------------*/ 15 16#include <nn/os/cache.h> 17 18namespace nw { 19namespace snd { 20namespace internal { 21namespace driver { 22 23namespace 24{ 25 26u16 GetSDKFormatFromSampleFormat( SampleFormat sampleFormat ) 27{ 28 switch( sampleFormat ) 29 { 30 case SAMPLE_FORMAT_DSP_ADPCM: 31 return AX_PB_FORMAT_ADPCM; 32 33 case SAMPLE_FORMAT_PCM_S8: 34 return AX_PB_FORMAT_PCM8; 35 36 /* 37 case SAMPLE_FORMAT_PCM_S16_BE: 38 case SAMPLE_FORMAT_PCM_S16_LE: 39 */ 40 case SAMPLE_FORMAT_PCM_S16: 41 return AX_PB_FORMAT_PCM16; 42 43 case SAMPLE_FORMAT_IMA_ADPCM: 44 default: 45 NW_ASSERTMSG( false, "Invalid format\n" ); 46 return AX_PB_FORMAT_ADPCM; 47 } 48} 49 50} // anonymous namespace 51 52 53HardwareChannel::DspAddress HardwareChannel::GetDspAddressBySample( 54 const void* baseAddress, 55 u32 samples, 56 SampleFormat format ) 57{ 58 if ( baseAddress != NULL ) 59 { 60 baseAddress = reinterpret_cast<const void*>( OS_CachedToPhysical( baseAddress ) ); 61 } 62 63 HardwareChannel::DspAddress addr = 0; 64 65 switch ( format ) 66 { 67 case SAMPLE_FORMAT_DSP_ADPCM: 68 addr = 69 ( reinterpret_cast<HardwareChannel::DspAddress>( baseAddress ) << 1 ) + 70 ( samples / 14 ) * 16 + ( samples % 14 ) + 2 71 ; 72 break; 73 74 case SAMPLE_FORMAT_PCM_S8: 75 addr = 76 reinterpret_cast<HardwareChannel::DspAddress>( baseAddress ) + 77 samples 78 ; 79 break; 80 81 case SAMPLE_FORMAT_PCM_S16: 82 addr = 83 ( reinterpret_cast<HardwareChannel::DspAddress>( baseAddress ) >> 1 ) + 84 samples 85 ; 86 break; 87 88 case SAMPLE_FORMAT_IMA_ADPCM: 89 default: 90 NW_ASSERTMSG( false, "Invalid format\n" ); 91 break; 92 } 93 94 return addr; 95} 96 97u32 HardwareChannel::GetSampleByDspAddress( 98 const void* baseAddress, 99 DspAddress addr, 100 SampleFormat format ) 101{ 102 if ( baseAddress != NULL ) 103 { 104 baseAddress = reinterpret_cast<const void*>( OS_CachedToPhysical( baseAddress ) ); 105 } 106 107 u32 samples = 0; 108 109 switch ( format ) 110 { 111 case SAMPLE_FORMAT_DSP_ADPCM: 112 samples = addr - ( reinterpret_cast<DspAddress>( baseAddress ) << 1 ); 113 samples = ( samples / 16 ) * 14 + ( samples % 16 ) - 2; 114 break; 115 116 case SAMPLE_FORMAT_PCM_S8: 117 samples = addr - reinterpret_cast<DspAddress>( baseAddress ); 118 break; 119 120 case SAMPLE_FORMAT_PCM_S16: 121 samples = addr - ( reinterpret_cast<DspAddress>( baseAddress ) >> 1 ); 122 break; 123 124 default: 125 NW_ASSERTMSG( false, "Invalid format\n" ); 126 break; 127 } 128 129 return samples; 130} 131 132void HardwareChannel::Initialize() 133{ 134} 135 136void HardwareChannel::OnInitialize() 137{ 138} 139 140void HardwareChannel::SetParamBlock( ParameterBlock* vpb ) 141{ 142 NW_NULL_ASSERT( vpb ); 143 m_pVpb = vpb; 144 m_SyncFlag = 0; 145 m_IsFirstVeUpdate = true; 146} 147 148void HardwareChannel::Sync() 149{ 150 if ( ! IsAvailable() ) return; 151 152 m_pVpb->sync |= m_SyncFlag; 153 m_SyncFlag = 0; 154} 155 156bool HardwareChannel::IsPlayFinished() const 157{ 158 if ( m_pWaveData == NULL ) return false; 159 160 DspAddress dspAddr = GetCurrentPlayingDspAddress(); 161 162 const void* zeroBuffer = HardwareManager::GetInstance().GetZeroBufferAddress(); 163 164 DspAddress beginPos = GetDspAddressBySample( zeroBuffer, 0, m_Format ); 165 DspAddress endPos = beginPos; 166 switch ( m_Format ) 167 { 168 case SAMPLE_FORMAT_DSP_ADPCM: 169 endPos += ( HardwareManager::ZERO_BUFFER_SIZE << 1 ); 170 break; 171 case SAMPLE_FORMAT_PCM_S8: 172 endPos += ( HardwareManager::ZERO_BUFFER_SIZE ); 173 break; 174 /* 175 case SAMPLE_FORMAT_PCM_S16_BE: 176 case SAMPLE_FORMAT_PCM_S16_LE: 177 */ 178 case SAMPLE_FORMAT_PCM_S16: 179 endPos += ( HardwareManager::ZERO_BUFFER_SIZE >> 1 ); 180 break; 181 default: 182 NW_ASSERTMSG( false, "Invalid format\n" ); 183 return false; 184 } 185 186 if ( beginPos <= dspAddr && dspAddr < endPos ) { 187 return true; 188 } 189 190 return false; 191} 192 193void HardwareChannel::Run() 194{ 195 if ( IsAvailable() ) 196 { 197 AX_SetVoiceState( m_pVpb, AX_PB_STATE_RUN ); 198 } 199} 200 201void HardwareChannel::Stop() 202{ 203 if ( IsAvailable() ) 204 { 205 AX_SetVoiceState( m_pVpb, AX_PB_STATE_STOP ); 206 } 207} 208 209void HardwareChannel::StopAtPoint( const void* baseAddress, u32 samples ) 210{ 211 if ( ! IsAvailable() ) return; 212 213 const void* zeroBuffer = HardwareManager::GetInstance().GetZeroBufferAddress(); 214 215 DspAddress beginPos = GetDspAddressBySample( zeroBuffer, 0, m_Format ); 216 DspAddress endPos = GetDspAddressBySample( baseAddress, samples-1, m_Format ); 217 218 SetVoiceLoopAddr( beginPos ); 219 SetVoiceEndAddr( endPos ); 220 SetVoiceLoop( AXPBADDR_LOOP_OFF ); 221} 222 223void HardwareChannel::SetLoopFlag( bool loopFlag ) 224{ 225 if ( ! IsAvailable() ) return; 226 227 if ( loopFlag ) 228 { 229 SetVoiceLoop( AXPBADDR_LOOP_ON ); 230 } 231 else 232 { 233 SetVoiceLoop( AXPBADDR_LOOP_OFF ); 234 } 235} 236 237void HardwareChannel::SetVoiceLoopAddr( u32 addr ) 238{ 239 if ( ! IsAvailable() ) return; 240 241 m_pVpb->pb.addr.loopAddressHi = static_cast<u16>( addr >> 16 ); 242 m_pVpb->pb.addr.loopAddressLo = static_cast<u16>( addr & 0xFFFF ); 243 if ( ! ( m_pVpb->sync & AX_SYNC_USER_ADDR ) ) 244 { 245 m_pVpb->sync |= AX_SYNC_USER_LOOPADDR; 246 } 247} 248 249void HardwareChannel::SetVoiceEndAddr( u32 addr ) 250{ 251 if ( ! IsAvailable() ) return; 252 253 m_pVpb->pb.addr.endAddressHi = static_cast<u16>( addr >> 16 ); 254 m_pVpb->pb.addr.endAddressLo = static_cast<u16>( addr & 0xFFFF ); 255 if ( ! ( m_pVpb->sync & AX_SYNC_USER_ADDR ) ) 256 { 257 m_pVpb->sync |= AX_SYNC_USER_ENDADDR; 258 } 259} 260 261void HardwareChannel::SetVoiceLoop( u32 loop ) 262{ 263 if ( ! IsAvailable() ) return; 264 265 m_pVpb->pb.addr.loopFlag = static_cast<u16>( loop ); 266 if ( ! ( m_pVpb->sync & AX_SYNC_USER_ADDR ) ) 267 { 268 m_pVpb->sync |= AX_SYNC_USER_LOOP; 269 } 270} 271 272// パラメータ設定関数 273void HardwareChannel::SetAddr( 274 bool loopFlag, 275 const void* waveAddr, 276 u32 startOffset, 277 u32 loopStart, 278 u32 loopEnd 279) 280{ 281 if ( ! IsAvailable() ) return; 282 283 DspAddress startPos; 284 DspAddress loopPos; 285 DspAddress endPos; 286 if ( startOffset > loopEnd ) 287 { 288 // 開始位置が範囲外なのでノイズにならないようにゼロバッファを再生して終了 289 const void* zeroBuffer = HardwareManager::GetInstance().GetZeroBufferAddress(); 290 loopFlag = false; 291 startPos = GetDspAddressBySample( zeroBuffer, 0, m_Format ); 292 loopPos = GetDspAddressBySample( zeroBuffer, 0, m_Format ); 293 endPos = GetDspAddressBySample( zeroBuffer, 1, m_Format ); 294 } 295 else 296 { 297 if ( loopFlag ) 298 { 299 loopPos = GetDspAddressBySample( waveAddr, loopStart, m_Format ); 300 } 301 else 302 { 303 const void* zeroBuffer = HardwareManager::GetInstance().GetZeroBufferAddress(); 304 loopPos = GetDspAddressBySample( zeroBuffer, 0, m_Format ); 305 } 306 startPos = GetDspAddressBySample( waveAddr, startOffset, m_Format ); 307 endPos = GetDspAddressBySample( waveAddr, loopEnd-1, m_Format ); 308 } 309 310 AXPBADDR addr; 311 addr.loopFlag = static_cast<u16>( loopFlag ? AXPBADDR_LOOP_ON: AXPBADDR_LOOP_OFF ); 312 addr.format = GetSDKFormatFromSampleFormat( m_Format ); 313 addr.loopAddressHi = static_cast<u16>( loopPos >> 16 ); 314 addr.loopAddressLo = static_cast<u16>( loopPos & 0xFFFF ); 315 addr.endAddressHi = static_cast<u16>( endPos >> 16 ); 316 addr.endAddressLo = static_cast<u16>( endPos & 0xFFFF ); 317 addr.currentAddressHi = static_cast<u16>( startPos >> 16 ); 318 addr.currentAddressLo = static_cast<u16>( startPos & 0xFFFF ); 319 320 AX_SetVoiceAddr( m_pVpb, const_cast<AXPBADDR*>( &addr ) ); 321} 322 323void HardwareChannel::SetDspAdpcm( const DspAdpcmParam* param ) 324{ 325 if ( ! IsAvailable() ) return; 326 327 DspAdpcmParameterBlock adpcm; 328 switch ( m_Format ) 329 { 330 case SAMPLE_FORMAT_DSP_ADPCM: 331 NW_NULL_ASSERT( param ); 332 (void)std::memcpy( adpcm.a, param->coef, sizeof(u16)*16 ); 333 adpcm.gain = 0; // param->gain; 334 adpcm.predScale = param->predScale; 335 adpcm.yn1 = static_cast<u16>( param->yn1 ); 336 adpcm.yn2 = static_cast<u16>( param->yn2 ); 337 break; 338 339#if 0 // ほかのフォーマットで SetAdpcm() 関数に入ることは無い 340 /* 341 case SAMPLE_FORMAT_PCM_S16_BE: 342 case SAMPLE_FORMAT_PCM_S16_LE: 343 */ 344 case SAMPLE_FORMAT_PCM_S16: 345 (void)std::memset( adpcm.a, 0, sizeof(u16)*16 ); 346 adpcm.gain = 0x0800; 347 adpcm.predScale = 0; 348 adpcm.yn1 = 0; 349 adpcm.yn2 = 0; 350 break; 351 case SAMPLE_FORMAT_PCM_S8: 352 (void)std::memset( adpcm.a, 0, sizeof(u16)*16 ); 353 adpcm.gain = 0x0100; 354 adpcm.predScale = 0; 355 adpcm.yn1 = 0; 356 adpcm.yn2 = 0; 357 break; 358 case SAMPLE_FORMAT_IMA_ADPCM: 359#endif 360 default: 361 NW_ASSERTMSG( false, "Invalid format\n" ); 362 break; 363 } 364 365 std::memcpy( &m_pVpb->pb.adpcm, &adpcm, sizeof( adpcm ) ); 366 m_SyncFlag |= AX_SYNC_USER_ADPCM; 367} 368 369void HardwareChannel::SetDspAdpcmLoop( const DspAdpcmLoopParam* param ) 370{ 371 if ( ! IsAvailable() ) return; 372 373 DspAdpcmLoopParameterBlock adpcmloop; 374 if ( m_Format == SAMPLE_FORMAT_DSP_ADPCM ) 375 { 376 NW_NULL_ASSERT( param ); 377 adpcmloop.loopPredScale = param->loopPredScale; 378 adpcmloop.loopYn1 = static_cast<u16>( param->loopYn1 ); 379 adpcmloop.loopYn2 = static_cast<u16>( param->loopYn2 ); 380 } 381 else 382 { 383 adpcmloop.loopPredScale = 0; 384 adpcmloop.loopYn1 = 0; 385 adpcmloop.loopYn2 = 0; 386 } 387 388 std::memcpy( &m_pVpb->pb.adpcmLoop, &adpcmloop, sizeof( adpcmloop ) ); 389 m_SyncFlag |= AX_SYNC_USER_ADPCMLOOP; 390} 391 392void HardwareChannel::SetSrcType( SrcType type, f32 pitch ) 393{ 394 if ( ! IsAvailable() ) return; 395 396 u16 src = AX_PB_SRCSEL_POLYPHASE; // ひとまず初期化 397 u16 coef = AX_PB_COEFSEL_16KHZ; 398 399 if ( type == SRC_TYPE_4TAP ) 400 { 401 f32 ratio = GetDspRatio( pitch ); 402 403 if ( ratio > 4.0f/3.0f ) coef = AX_PB_COEFSEL_8KHZ; 404 else if ( ratio > 1.0f ) coef = AX_PB_COEFSEL_12KHZ; 405 // else coef = AX_PB_COEFSEL_16KHZ; 406 // デフォルトで 16KHZ に設定されている。 407 } 408 else if ( type == SRC_TYPE_LINEAR ) 409 { 410 src = AX_PB_SRCSEL_LINEAR; 411 } 412 else 413 { 414 src = AX_PB_SRCSEL_NONE; 415 } 416 417 m_pVpb->pb.srcSelect = src; 418 m_pVpb->pb.coefSelect = coef; 419 420 m_SyncFlag |= AX_SYNC_USER_SRCSELECT; 421} 422 423void HardwareChannel::SetSrc( f32 ratio, bool initialUpdate ) 424{ 425 if ( ! IsAvailable() ) return; 426 427 if ( initialUpdate ) 428 { 429 ratio = GetDspRatio( ratio ); 430 ratio = nw::ut::Clamp( ratio, 0.0f, 65535.0f ); 431 432 u32 srcBits = static_cast<u32>( 0x00010000 * ratio ); 433 434 AXPBSRC src; 435 src.ratioHi = static_cast<u16>( srcBits >> 16 ); 436 src.ratioLo = static_cast<u16>( srcBits & 0xFFFF ); 437 438 src.currentAddressFrac = 0; 439 src.last_samples[0] = 0; 440 src.last_samples[1] = 0; 441 src.last_samples[2] = 0; 442 src.last_samples[3] = 0; 443 444 std::memcpy( &m_pVpb->pb.src, &src, sizeof( src ) ); 445 m_SyncFlag &= ~AX_SYNC_USER_SRCRATIO; 446 m_SyncFlag |= AX_SYNC_USER_SRC; 447 } 448 else 449 { 450 static const u32 SRC_RATIO_BASE = 0x10000; 451 u32 r = static_cast<u32>( GetDspRatio(ratio) * SRC_RATIO_BASE ); 452 m_pVpb->pb.src.ratioHi = static_cast<u16>( r >> 16 ); 453 m_pVpb->pb.src.ratioLo = static_cast<u16>( r & 0xFFFF ); 454 if ( ! ( m_SyncFlag & AX_SYNC_USER_SRC ) ) 455 { 456 m_SyncFlag |= AX_SYNC_USER_SRCRATIO; 457 } 458 } 459} 460 461f32 HardwareChannel::GetDspRatio( f32 ratio ) const 462{ 463 return ratio * m_SampleRate / AX_IN_SAMPLES_PER_SEC; 464} 465 466void HardwareChannel::SetMixParam( const MixParam& param ) 467{ 468 if ( ! IsAvailable() ) return; 469 470 AXPBMIX mix; 471 472 // mix構造体にvolumeを設定 473 mix.main.l = static_cast<u16>(param.mainBus[nn::snd::CHANNEL_INDEX_FRONT_LEFT]); 474 mix.main.r = static_cast<u16>(param.mainBus[nn::snd::CHANNEL_INDEX_FRONT_RIGHT]); 475 476 mix.aux[ 0 ].l = static_cast<u16>(param.auxBusA[nn::snd::CHANNEL_INDEX_FRONT_LEFT]); 477 mix.aux[ 0 ].r = static_cast<u16>(param.auxBusA[nn::snd::CHANNEL_INDEX_FRONT_RIGHT]); 478 479 mix.aux[ 1 ].l = static_cast<u16>(param.auxBusB[nn::snd::CHANNEL_INDEX_FRONT_LEFT]); 480 mix.aux[ 1 ].r = static_cast<u16>(param.auxBusB[nn::snd::CHANNEL_INDEX_FRONT_RIGHT]); 481 482 SetVoiceMix( mix ); 483} 484 485void HardwareChannel::SetVolume( f32 volume ) 486{ 487 if ( ! IsAvailable() ) return; 488 489 int vol = static_cast<int>(volume * static_cast<f32>( VOICE_GAIN_MAX ) ); 490 vol = nw::ut::Clamp( vol, 0, 0xffff ); 491 492 if ( IsPlaying() ) { 493 m_pVpb->pb.ve.originVolume = m_pVpb->pb.ve.targetVolume; 494 m_pVpb->pb.ve.targetVolume = vol; 495 } 496 else { 497 m_pVpb->pb.ve.originVolume = m_pVpb->pb.ve.targetVolume = vol; 498 } 499} 500 501void HardwareChannel::SetVoiceMix( const AXPBMIX& mix, bool immediatelySync ) 502{ 503 if ( ! IsAvailable() ) return; 504 505 if ( IsPlaying() ) { 506 m_pVpb->pb.mix.main.originL = m_pVpb->pb.mix.main.l; 507 m_pVpb->pb.mix.main.originR = m_pVpb->pb.mix.main.r; 508 m_pVpb->pb.mix.main.l = mix.main.l; 509 m_pVpb->pb.mix.main.r = mix.main.r; 510 511 for ( int i=0; i<AX_AUX_BUS_NUM ;i++){ 512 m_pVpb->pb.mix.aux[i].originL = m_pVpb->pb.mix.aux[i].l; 513 m_pVpb->pb.mix.aux[i].originR = m_pVpb->pb.mix.aux[i].r; 514 m_pVpb->pb.mix.aux[i].l = mix.aux[i].l; 515 m_pVpb->pb.mix.aux[i].r = mix.aux[i].r; 516 } 517 } 518 else 519 { 520 m_pVpb->pb.mix.main.originL = m_pVpb->pb.mix.main.l = mix.main.l; 521 m_pVpb->pb.mix.main.originR = m_pVpb->pb.mix.main.r = mix.main.r; 522 523 for ( int i=0; i<AX_AUX_BUS_NUM ;i++){ 524 m_pVpb->pb.mix.aux[i].originL = m_pVpb->pb.mix.aux[i].l = mix.aux[i].l; 525 m_pVpb->pb.mix.aux[i].originR = m_pVpb->pb.mix.aux[i].r = mix.aux[i].r; 526 } 527 } 528 529 if ( immediatelySync ) m_pVpb->sync |= AX_SYNC_USER_MIX | AX_SYNC_USER_MIXCTRL; 530 else m_SyncFlag |= AX_SYNC_USER_MIX | AX_SYNC_USER_MIXCTRL; 531} 532 533HardwareChannel::DspAddress HardwareChannel::GetCurrentPlayingDspAddress() const 534{ 535 if ( ! IsAvailable() ) return 0; 536 537 DspAddress dspAddr = static_cast<DspAddress>( 538 ( m_pVpb->pb.addr.currentAddressHi << 16 ) 539 + m_pVpb->pb.addr.currentAddressLo ); 540 return dspAddr; 541} 542 543HardwareChannel::DspAddress HardwareChannel::GetLoopStartDspAddress() const 544{ 545 if ( ! IsAvailable() ) return 0; 546 547 DspAddress dspAddr = static_cast<DspAddress>( 548 ( m_pVpb->pb.addr.loopAddressHi << 16 ) 549 + m_pVpb->pb.addr.loopAddressLo ); 550 return dspAddr; 551} 552 553HardwareChannel::DspAddress HardwareChannel::GetLoopEndDspAddress() const 554{ 555 if ( ! IsAvailable() ) return 0; 556 557 DspAddress dspAddr = static_cast<DspAddress>( 558 ( m_pVpb->pb.addr.endAddressHi << 16 ) 559 + m_pVpb->pb.addr.endAddressLo ); 560 return dspAddr; 561} 562 563bool HardwareChannel::IsPlaying() const 564{ 565 return IsAvailable() && ( m_pVpb->pb.state == AX_PB_STATE_RUN ); 566} 567 568bool HardwareChannel::IsCurrentAddressCovered( 569 const void* begin, const void* end ) const 570{ 571 if ( ! IsAvailable() ) return false; 572 573 DspAddress dspAddr = GetCurrentPlayingDspAddress(); 574 575 u32 samples = Util::GetSampleByByte( static_cast<u32>( 576 reinterpret_cast<const u8*>( end ) - reinterpret_cast<const u8*>( begin ) ), 577 m_Format ); 578 DspAddress dspAddressBegin = GetDspAddressBySample( 579 begin, 580 0, 581 m_Format 582 ); 583 DspAddress dspAddressEnd = GetDspAddressBySample( 584 begin, 585 samples, 586 m_Format 587 ); 588 589 if ( ( dspAddressBegin <= dspAddr ) && ( dspAddr < dspAddressEnd ) ) 590 { 591 return true; 592 } 593 594 return false; 595} 596 597u32 HardwareChannel::GetPlayPosition() const 598{ 599 if ( ! IsAvailable() ) { return 0; } 600 601 if ( m_pWaveData == NULL ) { return 0; } 602 603 u32 end_samples = GetSampleByDspAddress( 604 m_pWaveData, 605 GetLoopEndDspAddress(), 606 m_Format ) + 1; 607 608 if ( IsPlayFinished() ) 609 { 610 return end_samples; 611 } 612 613 u32 samples = GetSampleByDspAddress( 614 m_pWaveData, 615 GetCurrentPlayingDspAddress(), 616 m_Format ); 617 618 if ( samples > end_samples ) samples = end_samples; 619 620 return samples; 621} 622 623} // namespace nw::snd::internal::driver 624} // namespace nw::snd::internal 625} // namespace nw::snd 626} // namespace nw 627 628 629