touch5有什么用 Sound怎么用?

&主题:BOSE SoundTouch™ Portable WIFI 音箱 怎么样?
泡网分: 22.85
注册: 2001年08月
最近比较迷这个,从米国亚马逊定了一下,还没有寄到。
基于家里的WIFI网络,可以直接播放网上电台的音乐(用电脑或手机选择,机器上可以预定义6个电台),不需要电脑和手机;用AIRPLAY直接播放iphone手机的音乐;或者播放电脑里面的音乐库。
在卖场听了一段时间,效果还不错,选择方式也很有趣。
原来有一个SoundLink Bluetooth Mobile speaker II,效果真是非常好,可惜用了几年,蓝牙坏了,只能接个APPLE EXPRESS来做AIRPLAY。
本帖最后由 钛十三 于
17:12 编辑
&版权所有:&&桂ICP备号&增值电信业务经营许可证2863人阅读
SoundTouch音频处理库初始化流程剖析
定义一个变量SoundTouch m_SoundT
SoundTouch的派生关系
FIFOSamplePipe-&FIFOProcessor-&SoundTouch (流程[1])
因此首先构造基类FIFOSamplePipe,接着派生出FIFOProcessor,然后才以FIFOProcessor派生出SoundTouch。这里不得不提一下老外的C++水平真的很高,在这里基本上把类的继承发挥到了极致。能够分析这样的代码简直就是一种享受。先看一下基类FIFOSamplePipe,如下定义:
class FIFOSamplePipe
&&& // virtual default destructor
&&& virtual ~FIFOSamplePipe() {}
&&& /// Returns a pointer to the beginning of the output samples.
&&& /// This function is provided for accessing the output samples directly.
&&& /// Please be careful for not to corrupt the book-keeping!
&&& /// When using this function to output samples, also remember to 'remove' the
&&& /// output samples from the buffer by calling the
&&& /// 'receiveSamples(numSamples)' function
&&& virtual SAMPLETYPE *ptrBegin() = 0;
&&& /// Adds 'numSamples' pcs of samples from the 'samples' memory position to
&&& /// the sample buffer.
&&& virtual void putSamples(const SAMPLETYPE *samples,& ///& Pointer to samples.
&&&&&&&&&&&&&&&&&&&&&&&&&&& uint numSamples&&&&&&&&&&&& ///& Number of samples to insert.
&&&&&&&&&&&&&&&&&&&&&&&&&&& ) = 0;
&&& // Moves samples from the 'other' pipe instance to this instance.
&&& void moveSamples(FIFOSamplePipe &other& ///& Other pipe instance where from the receive the data.
&&&&&&&& )
&&&&&&& int oNumSamples = other.numSamples();
&&&&&&& putSamples(other.ptrBegin(), oNumSamples);
&&&&&&& other.receiveSamples(oNumSamples);
&&& /// Output samples from beginning of the sample buffer. Copies requested samples to
&&& /// output buffer and removes them from the sample buffer. If there are less than
&&& /// 'numsample' samples in the buffer, returns all that available.
&&& /// /return Number of samples returned.
&&& virtual uint receiveSamples(SAMPLETYPE *output, ///& Buffer where to copy output samples.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& uint maxSamples&&&&&&&&&&&&&&&& ///& How many samples to receive at max.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ) = 0;
&&& /// Adjusts book-keeping so that given number of samples are removed from beginning of the
&&& /// sample buffer without copying them anywhere.
&&& /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
&&& /// with 'ptrBegin' function.
&&& virtual uint receiveSamples(uint maxSamples&& ///& Remove this many samples from the beginning of
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ) = 0;
&&& /// Returns number of samples currently available.
&&& virtual uint numSamples() const = 0;
&&& // Returns nonzero if there aren't any samples available for outputting.
&&& virtual int isEmpty() const = 0;
&&& /// Clears all the samples.
&&& virtual void clear() = 0;
这里没有实现FIFOSamplePipe类的构造函数,因此系统隐性的调用了默认的自动生成的FIFOSamplePipe()。当然他应该没有做任何的初始化,同样也不需要做任何的初始化。通过定义virtual ~FIFOSamplePipe() {}虚析构函数,使得new一个子类,例如:FIFOSamplePipe* a = new FIFOProcessor,当a销毁的时候都会执行子类FIFOProcessor的析构函数,保证不管多少层继承都会一次过全部销毁,这是作为一个基类的特点。类的继承和多态果然是C++最为强悍的一部分,有助于编写重复性很高的类。通过看这个基类的声明,我们可以留意到除了定义大多数虚函数之外,他唯独实现了moveSamples这个函数,也就是子类如果没有override moveSamples,都将调用这个方法。他做的处理也相对来说很简单,根据注释,我们不难理解,正是这个函数实现了各个派生类之间的数据共享传递的接口。
// Moves samples from the 'other' pipe instance to this instance.
moveSamples(FIFOSamplePipe &other& ///& Other pipe instance where from the receive the data.
&&&&&&& int oNumSamples = other.numSamples();
&&&&&&& putSamples(other.ptrBegin(), oNumSamples);
&&&&&&& other.receiveSamples(oNumSamples);
在创建SoundTouch类之前,经过(流程[1])的前面两个步骤,他们都隐形的调用了默认的析构函数,由于基类FIFOSamplePipe没有实现构造函数,我们可以默认他不做任何的初始化,然后FIFOProcessor简单的把成员变量FIFOSamplePipe *一个指向基类的指针赋值简单做了一下初始化,让他指向NULL。
FIFOProcessor()
output = NULL;
现在回到SoundTouch的构造函数,在构造完前面两个类之后,他终于可以调用自己的默认构造函数
SoundTouch::SoundTouch()
&&& // Initialize rate transposer and tempo changer instances
&&& pRateTransposer = RateTransposer::newInstance();
&&& pTDStretch = TDStretch::newInstance();
&&& setOutPipe(pTDStretch);
&&& rate = tempo = 0;
&&& virtualPitch =
&&& virtualRate =
&&& virtualTempo = 1.0;
&&& calcEffectiveRateAndTempo();
&&& channels = 0;
&&& bSrateSet = FALSE;
看一下SoundTouch类的成员变量
class SoundTouch : public FIFOProcessor
&&& /// Rate transposer class instance
&&& class RateTransposer *pRateT
&&& /// Time-stretch class instance
&&& class TDStretch *pTDS
&&& /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
&&& float virtualR
&&& /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
&&& float virtualT
&&& /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
&&& float virtualP
&&& /// Flag: Has sample rate been set?
&&& BOOL& bSrateS
&&& /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and
&&& /// 'virtualPitch' parameters.
&&& void calcEffectiveRateAndTempo();
protected :
&&& /// Number of channels
&&& /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
&&& /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
根据构造函数他实例化pRateTransposer,pTDStretch这两个类。
首先看一下RateTransposer类的成员函数newInstance,通过一个宏定义INTEGER_SAMPLES来new一个定点还是浮点处理的类,马上就可以判断不管RateTransposerInteger还是RateTransposerFloat都应该直接从RateTransposer派生。(假设INTEGER_SAMPLES被定义)他将构造一个RateTransposerInteger。
RateTransposer *RateTransposer::newInstance()
#ifdef INTEGER_SAMPLES
&&& return ::new RateTransposerI
&&& return ::new RateTransposerF
看一下RateTransposerInteger类的定义,不出所料果然由RateTransposer派生
class RateTransposer : public FIFOProcessor
protected:
&&& FIFOSampleBuffer storeB
&&& /// Buffer for keeping samples between transposing & anti-alias filter
&&& FIFOSampleBuffer tempB
&&& /// Output sample buffer
&&& FIFOSampleBuffer outputB
上诉两个类他们和基类之间存在这样的关系:
FIFOSamplePipe-&FIFOProcessor-&RateTransposer-&RateTransposerInteger
这里的构造过程不同的是:RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
RateTransposer构造函数指明了父类FIFOProcessor的构造形式FIFOProcessor(&outputBuffer)
FIFOProcessor(FIFOSamplePipe *pOutput&& ///& Output pipe.
output = pO
RateTransposer把类成员变量outputBuffer作为传递函数参数,这里可能大家就会很奇怪,代码里面根本还没有实例化RateTransposer类,他怎么可能存在一个FIFOSampleBuffer outputB其实正是体现了c++的多态性,这里传入的实际上是一个__vfptr数组,这个数组就是指向实例化各个派生类的这个变量的指针数组。这下子明白了。__vfptr[0]不一定有值,但是__vfptr肯定是一个存在的值。构造完FIFOProcessor,此时要构造RateTransposer,他有三个FIFOSampleBuffer类定义。
class FIFOSampleBuffer : public FIFOSamplePipe
与基类的继承关系
FIFOSamplePipe-&FIFOSampleBuffer
/// Constructor
FIFOSampleBuffer(int numChannels = 2&&&& ///& Number of channels, 1=mono, 2=stereo.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ///& Default is stereo.
他没有定义不带参的构造函数,因此这个带参数的构造函数将以默认的方式给调用
FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)
&&& assert(numChannels & 0);
&&& sizeInBytes = 0; // reasonable initial value
&&& buffer = NULL;
&&& bufferUnaligned = NULL;
&&& samplesInBuffer = 0;
&&& bufferPos = 0;
&&& channels = (uint)numC
&&& ensureCapacity(32);&&&& // allocate initial capacity
FIFOSampleBuffer的构造函数将被调用三次。
现在终于可以执行RateTransposer的构造函数
// Constructor
RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
&&& numChannels = 2;
&&& bUseAAFilter = TRUE;
&&& fRate = 0;
&&& // Instantiates the anti-alias filter with default tap length
&&& // of 32
&&& pAAFilter = new AAFilter(32);
首先看一下AAFilter的相关定义
class AAFilter
protected:
&&& class FIRFilter *pFIR;
&&& /// Low-pass filter cut-off frequency, negative = invalid
&&& double cutoffF
&&& /// num of filter taps
&&& /// Calculate the FIR coefficients realizing the given cutoff-frequency
&&& void calculateCoeffs();
&&& AAFilter(uint length);
&&& ~AAFilter();
&&& /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling
&&& /// frequency (nyquist frequency = 0.5). The filter will cut off the
&&& /// frequencies than that.
&&& void setCutoffFreq(double newCutoffFreq);
&&& /// Sets number of FIR filter taps, i.e. ~filter complexity
&&& void setLength(uint newLength);
&&& uint getLength()
&&& /// Applies the filter to the given sequence of samples.
&&& /// Note : The amount of outputted samples is by value of 'filter length'
&&& /// smaller than the amount of input samples.
&&& uint evaluate(SAMPLETYPE *dest,
&&&&&&&&&&&&&&&&& const SAMPLETYPE *src,
&&&&&&&&&&&&&&&&& uint numSamples,
&&&&&&&&&&&&&&&&& uint numChannels)
在其构造函数中初始化了一个指向class FIRFilter的指针
AAFilter::AAFilter(uint len)
&&& pFIR = FIRFilter::newInstance();
&&& cutoffFreq = 0.5;
&&& setLength(len);
首先我们看看FIRFilter类成员函数newInstance(),嘿嘿,在这里我们发现了一个非常有用的函数detectCPUextensions();通过这个函数我们可以判断cpu到底支持什么类型的多媒体指令集。根据注释我们也可以很快理解。detectCPUextensions收藏了。他的实现就在Cpu_detect_x86_win.cpp的实现中。美中不足的是,他只能检测x86结构体系的CPU。可能我多想了。根据本人电脑的配置(采用的赛扬cpu),所以只支持mmx指令。
FIRFilter * FIRFilter::newInstance()
&&& uint uE
&&& uExtensions = detectCPUextensions();
&&& // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU
#ifdef ALLOW_MMX
&&& // MMX routines available only with integer sample types
&&& if (uExtensions & SUPPORT_MMX)
&&&&&&& return ::new FIRFilterMMX;
#endif // ALLOW_MMX
#ifdef ALLOW_SSE
&&& if (uExtensions & SUPPORT_SSE)
&&&&&&& // SSE support
&&&&&&& return ::new FIRFilterSSE;
#endif // ALLOW_SSE
#ifdef ALLOW_3DNOW
&&& if (uExtensions & SUPPORT_3DNOW)
&&&&&&& // 3DNow! support
&&&&&&& return ::new FIRFilter3DN
#endif // ALLOW_3DNOW
&&&&&&& // ISA optimizations not supported, use plain C version
&&&&&&& return ::new FIRF
为此他将通过这个判断构造返回一个FIRFilterMMX类
if (uExtensions & SUPPORT_MMX)
&&&&&&& return ::new FIRFilterMMX;
查看FIRFilterMMX的类定义class FIRFilterMMX : public FIRFilter,他从FIRFilter派生。成员函数uint FIRFilterMMX::evaluateFilterStereo引起了我的高度注意,主要的算法采用MMX指令集来完成某些声音计算。这个就是我们需要的Rate的核心算法。不同指令集的实现,可以参考FIRFilter3DNow,FIRFilterSSE,默认是FIRFilter的evaluateFilterStereo函数的实现。
// mmx-optimized version of the filter routine for stereo sound
uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const
&&& // Create stack copies of the needed member variables for asm routines :
&&& uint i,
&&& __m64 *pVdest = (__m64*)
&&& if (length & 2) return 0;
&&& for (i = 0; i & (numSamples - length) / 2; i ++)
&&&&&&& __m64 accu1;
&&&&&&& __m64 accu2;
&&&&&&& const __m64 *pVsrc = (const __m64*)
&&&&&&& const __m64 *pVfilter = (const __m64*)filterCoeffsA
&&&&&&& accu1 = accu2 = _mm_setzero_si64();
&&&&&&& for (j = 0; j & lengthDiv8 * 2; j ++)
&&&&&&&&&&& __m64 temp1, temp2;
&&&&&&&&&&& temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]);& // = l2 l0 r2 r0
&&&&&&&&&&& temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]);& // = l3 l1 r3 r1
&&&&&&&&&&& accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0]));& // += l2*f2+l0*f0
r2*f2+r0*f0
&&&&&&&&&&& accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1]));& // += l3*f3+l1*f1
r3*f3+r1*f1
&&&&&&&&&&& temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]);& // = l4 l2 r4 r2
&&&&&&&&&&& accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0]));& // += l3*f2+l1*f0
r3*f2+r1*f0
&&&&&&&&&&& accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1]));& // += l4*f3+l2*f1
r4*f3+r2*f1
&&&&&&&&&&& // accu1 += l2*f2+l0*f0 r2*f2+r0*f0
&&&&&&&&&&& //&&&&&& += l3*f3+l1*f1 r3*f3+r1*f1
&&&&&&&&&&& // accu2 += l3*f2+l1*f0 r3*f2+r1*f0
&&&&&&&&&&& //&&&&&&&&& l4*f3+l2*f1 r4*f3+r2*f1
&&&&&&&&&&& pVfilter += 2;
&&&&&&&&&&& pVsrc += 2;
&&&&&&& // accu &&= resultDivFactor
&&&&&&& accu1 = _mm_srai_pi32(accu1, resultDivFactor);
&&&&&&& accu2 = _mm_srai_pi32(accu2, resultDivFactor);
&&&&&&& // pack 2*2*32bits =& 4*16 bits
&&&&&&& pVdest[0] = _mm_packs_pi32(accu1, accu2);
&&&&&&& src += 4;
&&&&&&& pVdest ++;
&& _m_empty();& // clear emms state
&&& return (numSamples & 0xfffffffe) -
因此,如果把SoundTouch移植到arm等没有多媒体指令集的CPU时,应使用FIRFilter的evaluateFilterStere函数。执行完这里,终于可以真正意义上构造我们的RateTransposerInteger()。在构造函数中:
RateTransposerInteger::RateTransposerInteger() : RateTransposer()
&&& // Notice: use local function calling syntax for sake of clarity,
&&& // to indicate the fact that C++ constructor can't call virtual functions.
&&& RateTransposerInteger::resetRegisters();
&&& RateTransposerInteger::setRate(1.0f);
}进行了一些必要的初始化。至此pRateTransposer = RateTransposer::newInstance();实例化完毕。至于pTDStretch = TDStretch::newInstance();下回分晓。
本文来自CSDN博客,转载请标明出处:
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:413273次
积分:5979
积分:5979
排名:第1275名
原创:175篇
转载:108篇
评论:156条
阅读:4402
(1)(1)(1)(3)(10)(8)(18)(3)(8)(7)(2)(2)(9)(3)(8)(2)(2)(4)(1)(6)(1)(11)(44)(7)(28)(7)(15)(13)(7)(1)(3)(1)(6)(4)(1)(1)(1)(1)(1)(1)(4)(4)(6)(6)(1)(1)(9)Amazon CAPTCHA
请输入您在这个图片中看到的字符:
& , , Inc. or its affiliatesbose全新soundtouch portable - 上海杨浦家用电器 - 百姓网
&&关注百姓微信公众号,尽享快捷刷新、信息推送、抽奖活动等众多微信功能您只需要:1 &用微信“扫一扫”右边的二维码2 &在微信中“关注”我们&|&|||||bose全新soundtouch portable&提示信息设置为“搞定了!”状态后,其他用户将无法查看您的联系方式。您确认搞定了这条信息吗?提示重新发布后可使用“刷新”将发布时间更新为最新时间,并将信息排到第一页。&&8月25日 20:58 &...次浏览 &信息编号: &1852130****(上海)&&百姓网号码保护功能介绍&&拨打百姓400转呼电话绝不收取您任何额外费用,该信息发布人仍能看到您的来电号码。联系时,请一定说明在百姓网看到的,谢谢!见面最安全,发现问题请举报。类型:& 价格:3400元地区:本人欲购bose家庭影院一套,附赠的soundto&&uch portable有意转让。3400元左右 影音电器 信息3580元&/&影音电器2980元&/&影音电器3280元&/&影音电器3000元&/&影音电器3300元&/&影音电器
赞助商链接
反馈建议描述:请填写描述手机号:请填写手机号请填写手机号10.

我要回帖

更多关于 touch5有什么用 的文章

 

随机推荐