1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     snd_HardwareChannel.cpp
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: 22284 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 #include <nw/snd/snd_HardwareChannel.h>
18 
19 #include <cstring>
20 #include <nw/snd/snd_HardwareManager.h>
21 #include <nw/snd/snd_HardwareChannelManager.h>
22 
23 #include NW_SND_ADAPTIVE_SOURCE( HardwareChannel )
24 
25 namespace nw {
26 namespace snd {
27 namespace internal {
28 namespace driver {
29 
30 /* ========================================================================
31         static function
32    ======================================================================== */
33 
CalcOffsetDspAdpcmParam(u16 * outPredScale,u16 * outYn1,u16 * outYn2,u32 offset,const void * dataAddr,const DspAdpcmParam & adpcmParam)34 void HardwareChannel::CalcOffsetDspAdpcmParam(
35     u16* outPredScale,
36     u16* outYn1,
37     u16* outYn2,
38     u32 offset,
39     const void* dataAddr,
40     const DspAdpcmParam& adpcmParam
41 )
42 {
43     DspAdpcmParameterBlock adpcm;
44     std::memcpy( adpcm.a, adpcmParam.coef, sizeof(u16)*16 );
45     adpcm.gain = 0; // adpcmParam.gain;
46     adpcm.predScale = adpcmParam.predScale;
47     adpcm.yn1 = adpcmParam.yn1;
48     adpcm.yn2 = adpcmParam.yn2;
49 
50     DspAddress currentPos = GetDspAddressBySample( dataAddr, 0, SAMPLE_FORMAT_DSP_ADPCM );
51     DspAddress endPos = GetDspAddressBySample( dataAddr, offset, SAMPLE_FORMAT_DSP_ADPCM );
52 
53     while ( currentPos < endPos )
54     {
55         // 8バイトごとのpred scaleを読み取る
56         if ( ! (currentPos & 0xf) )
57         {
58             u8 byte = *reinterpret_cast<u8*>( OS_PhysicalToCached( currentPos >> 1 ) );
59             adpcm.predScale = (u16)byte;
60 
61             currentPos += 2;
62         }
63 
64         u8 byte = *reinterpret_cast<u8*>( OS_PhysicalToCached( currentPos >> 1 ) );
65         u8 nibble;
66         if ( currentPos & 0x1 )
67         {
68             nibble = static_cast<u8>( byte & 0xf );
69         }
70         else
71         {
72             nibble = static_cast<u8>( byte >> 4 );
73         }
74 
75 #ifdef NW_PLATFORM_CTRWIN
76         AX_DecodeDspAdpcm( &adpcm, nibble );
77 #else
78         nn::dspsnd::CTR::Dspsnd::DecodeAdpcmNibble(
79                 reinterpret_cast<nn::dspsnd::CTR::DspsndAdpcmState*>(&adpcm),
80                 nibble );
81 #endif
82 
83         currentPos++;
84     }
85 
86     *outPredScale = adpcm.predScale;
87     *outYn1 = adpcm.yn1;
88     *outYn2 = adpcm.yn2;
89 }
90 
91 
92 
93 /* ========================================================================
94         member function
95    ======================================================================== */
HardwareChannel()96 HardwareChannel::HardwareChannel()
97 : m_pWaveData( NULL ),
98   m_IsReserveForFree( false ),
99   m_Callback( NULL ),
100   m_pCallbackData( NULL )
101 {
102     Initialize();
103 }
104 
~HardwareChannel()105 HardwareChannel::~HardwareChannel()
106 {
107 }
108 
109 
ClearParamBlock()110 void HardwareChannel::ClearParamBlock()
111 {
112     m_pVpb = NULL;
113     m_SyncFlag = 0;
114 }
115 
Initialize(const void * waveAddr,SampleFormat format,int sampleRate)116 void HardwareChannel::Initialize( const void* waveAddr, SampleFormat format, int sampleRate )
117 {
118     m_pWaveData = waveAddr;
119     m_Format = format;
120     m_SampleRate = sampleRate;
121 
122     OnInitialize();
123 }
124 
125 
126 
SetLoopStart(const void * baseAddress,u32 samples)127 void HardwareChannel::SetLoopStart( const void* baseAddress, u32 samples )
128 {
129     if ( ! IsAvailable() ) return;
130 
131     DspAddress dspAddress = GetDspAddressBySample(
132         baseAddress,
133         samples,
134         m_Format
135     );
136 
137     SetVoiceLoopAddr( dspAddress );
138 }
139 
SetLoopEnd(const void * baseAddress,u32 samples)140 void HardwareChannel::SetLoopEnd( const void* baseAddress, u32 samples )
141 {
142     if ( ! IsAvailable() ) return;
143 
144     DspAddress dspAddress = GetDspAddressBySample(
145         baseAddress,
146         samples-1,
147         m_Format
148     );
149 
150     SetVoiceEndAddr( dspAddress );
151 }
152 
IsDataAddressCovered(const void * begin,const void * end) const153 bool HardwareChannel::IsDataAddressCovered(
154         const void* begin, const void* end ) const
155 {
156     if ( ! IsAvailable() ) { return false; }
157 
158     if ( m_pWaveData == NULL ) { return false; }
159 
160     if ( begin <= m_pWaveData && m_pWaveData <= end )
161     {
162         return true;
163     }
164     else
165     {
166         return false;
167     }
168 }
169 
170 
SetLpf(u16)171 void HardwareChannel::SetLpf( u16 /*freq*/ ) {} // TODO:
SetBiquad(u8,f32)172 void HardwareChannel::SetBiquad( u8 /*filterType*/, f32 /*value*/ ) {} // TODO:
173 
SetPriority(u32)174 void HardwareChannel::SetPriority( u32 /*priority*/ ) {} // TODO:
175 
176 
ChannelCallback(void * callbackData)177 void HardwareChannel::ChannelCallback( void* callbackData )
178 {
179     ParameterBlock* dropVpb = reinterpret_cast<ParameterBlock*>( callbackData );
180     HardwareChannel* pChannel = reinterpret_cast<HardwareChannel*>( dropVpb->userContext );
181     NW_NULL_ASSERT( pChannel );
182 
183     pChannel->ClearParamBlock();
184 
185     // 解放処理に時間がかかるので、割り込み禁止期間が延びないように
186     // 後で処理を行うようにする。
187     HardwareChannelManager::GetInstance().ReserveForFreeHardwareChannel( pChannel );
188 }
189 
190 
191 
192 } // namespace nw::snd::internal::driver
193 } // namespace nw::snd::internal
194 } // namespace nw::snd
195 } // namespace nw
196