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