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