Symbian音频技术探究

 
Author: 孙东风
 
Symbian SDK下有个sound的项目,这个例子囊括了Symbian下的音频播放技术。
下面有Symbian中的音频技术:
     CMdaAudioToneUtility
Description
Generates tones on an audio capable device.
While this class is abstract, the static function constructs, initialises and returns a pointer to
an instance of a concrete class derived from this class. The concrete class is part of the MMF
implementation and is private.
 
从Class的Description中可以看出,这个类是用来播放tone的。
与其相对应的监听类为
MmdaAudioToneObserver
Description
An interface to a set of audio tone player callback functions.
The class is a mixin and is intended to be inherited by the client class which is observing the
audio tone playing operation. The functions encapsulated by this class are called when
specific events occur in the process of configuring the audio tone player utility and the
playing of a tone.
A reference to this object is passed as a parameter when constructing an audio tone player
utility, using the CMdaAudioToneUtility interface.
 
此监听类用来监视tone播放的操作,它封装了一些接口。在设置Player的属性和播放tone的过程中如果有特定的事件发生,就会去调用相应的接口。
在sound项目中对应的封装类如下所示:
先来看看类中声明了那些接口
#ifndef __CTONEADAPTER_H__
#define __CTONEADAPTER_H__
 
// INCLUDES
#include
#include
#include "audioadapter.h"
 
// CONSTANTS
// Frequency and duration of the tone to be played
static const TInt KSoundFrequency = 3000;   //声音的播放频率
static const TInt KSoundDuration = 5000000; //声音的播放时间
 
// FORWARD DECLARATIONS
class CSoundAppUi;
 
// CLASS DECLARATION
class CToneAdapter : public CBase,
                     public MAudioAdapter,
                     public MMdaAudioToneObserver
    {
    public:
        static CToneAdapter* NewL( CSoundAppUi& aAppUi );
        static CToneAdapter* NewLC( CSoundAppUi& aAppUi );
        virtual ~CToneAdapter();
 
    public: // from MAudioAdapter
        /**
        * PlayL
        * Begin playback of the tone.
        */
        void PlayL();
        /**
        * RecordL
        * Do nothing. Recording is not supported.
        */
        void RecordL();
        /**
        * StopL
        * Stop playback or recording of the tone.
        * Note that this implementation of the virtual function does not leave.
        */   
        void StopL();
        /**
        * UpdateMenuL
        * Update the menu aMenuPane to reflect the
        * current state of the audio tone utility.
        * Note that this implementation of the virtual function does not leave.
        * @param aMenuPane the menu pane to update
        */
        void UpdateMenuL( CEikMenuPane* aMenuPane );
        /**
        * Identify
        * Return an identifying string
        * @return An identification string
        */
        const TDesC& Identify();
 
    public: // from MMdaAudioToneObserver
 
        /**
        * MatoPrepareComplete
        * Handle the event when a tone utility initialisation
        * operation has completed.
        * @param aError indicates whether an error occurred.
        */
        void MatoPrepareComplete( TInt aError );
 
        /**
        * MatoPlayComplete
        * Handle the event when a tone playing operation has completed.
        * @param aError indicates whether an error occurred.
        */
        void MatoPlayComplete( TInt aError );
   
    private: // Constructors and destructor
        /**
        * CToneAdapter.
        * C++ default constructor.
        * Perform the first phase of two phase construction
        * @param aAppUi the Ui to use
        */
        CToneAdapter( CSoundAppUi& aAppUi );
        /**
        * ConstructL
        * 2nd phase constructor.
        * @param aRect Frame rectangle for container.
        */
        void ConstructL();
    private// Data
        /**
        * iMdaAudioToneUtility The audio tone utility object.
        * owned by CToneAdapter object.
        */
        CMdaAudioToneUtility* iMdaAudioToneUtility;
        /** iAppUi Reference to the application's UI object. **/
        CSoundAppUi& iAppUi;
        /**
        * itextResourceIdentifier. Textresource for identifier
        * owned by CToneAdapter object.
        */
        HBufC* itextResourceIdentifier;
    };
 
#endif // __CTONEADAPTER_H__
 
从类声明的接口中我们可以看出,这个类封装了 MAudioAdapter MMdaAudioToneObserver 中的接口,Mm daAudioToneObserver没什么好说的,是Symbian音频框架提供的一个接口,用来监听音频播放中的各种事件。
而MaudioAdapter是项目中的另外一个接口,其声明如下
#ifndef __MAUDIOADAPTER_H__
#define __MAUDIOADAPTER_H__
#include
class CEikMenuPane;
class MAudioAdapter
    {
    public: // New functions
        /**
        * PlayL
        * Play the audio utility.
        */        
        virtual void PlayL() = 0;
        /**
        * StopL
        * Stop the audio utility.
        */  
        virtual void StopL() = 0;
        /**
        * RecordL
        * Record using the audio utility ( if supported ).
        */
        virtual void RecordL() = 0;
        /**
        * UpdateMenuL
        * Update the menu aMenuPane to reflect the current
        * state of the audio utility.
        * @param aMenuPane the menu pane to update
        */
        virtual void UpdateMenuL( CEikMenuPane* aMenuPane ) = 0;
        /**
        * Identify
        * Return an identifying string
        * @return an identifier
        */
        virtual const TDesC& Identify() = 0;
 
    };
#endif // __MAUDIOADAPTER_H__
可以看出这是一个纯接口,抽象出了音频播放的一些共性的东西,然后“委托”给具体的播放类来实现。其中 CtoneAdapter就是一个具体的实现。
下面来具体看看 CtoneAdapter的实现
#include
#include
 
#include "sound.pan"
#include "sound.hrh"
#include "toneadapter.h"
#include "soundappui.h"
 
// C++ default constructor can NOT contain any code, that might leave.
CToneAdapter::CToneAdapter( CSoundAppUi& aAppUi ) : iAppUi( aAppUi )
    {
    // No implementation required
    }
 
// Two-phased constructor.
CToneAdapter* CToneAdapter::NewL( CSoundAppUi& aAppUi )
    {
    CToneAdapter* self = NewLC( aAppUi );
    CleanupStack::Pop( self );
    return self;
    }
 
// Two-phased constructor.
CToneAdapter* CToneAdapter::NewLC( CSoundAppUi& aAppUi )
    {
    CToneAdapter* self = new( ELeave )CToneAdapter( aAppUi );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }
 
// Symbian 2nd phase constructor can leave.
void CToneAdapter::ConstructL()
    {
 
    // Load a string from the resource file.
    // Identifying string for this audio utility.
     itextResourceIdentifier = CCoeEnv::Static()->AllocReadResourceL(
                                                            R_SOUN_MODE_TONER );
 
    iMdaAudioToneUtility = CMdaAudioToneUtility::NewL( *this );
 
    // Configure the audio tone utility to play a single tone
    // causes MMdaAudioToneObserver::MatoPrepareComplete to be called
    iMdaAudioToneUtility->PrepareToPlayTone( KSoundFrequency,
                                   TTimeIntervalMicroSeconds( KSoundDuration ) );
    }
 
// Destructor.
CToneAdapter::~CToneAdapter()
    {
    delete iMdaAudioToneUtility;   
    iMdaAudioToneUtility = NULL;
 
    // Delete private HBuf member for indetify
    delete itextResourceIdentifier;
    }
 
// Update Menu
void CToneAdapter::UpdateMenuL( CEikMenuPane* aMenuPane )
    {
    aMenuPane->SetItemDimmed( ESoundCmdPlay,   ETrue );
    aMenuPane->SetItemDimmed( ESoundCmdRecord, ETrue );
    aMenuPane->SetItemDimmed( ESoundCmdStop,   ETrue );
    aMenuPane->SetItemDimmed( ESoundCmdChange, ETrue );
   
    switch ( iMdaAudioToneUtility->State() )
        {
        case EMdaAudioToneUtilityNotReady:
            aMenuPane->SetItemDimmed( ESoundCmdChange, EFalse );
            break;
 
        case EMdaAudioToneUtilityPrepared:
            aMenuPane->SetItemDimmed( ESoundCmdPlay, EFalse );
            aMenuPane->SetItemDimmed( ESoundCmdChange, EFalse );
            break;
 
        case EMdaAudioToneUtilityPlaying:
            aMenuPane->SetItemDimmed( ESoundCmdStop, EFalse );
            break;
 
        default:
            User::Panic( KToneAdapter, KSoundPanicInvalidMdaState );
            break;
        }
    }
 
// Play the tone
void CToneAdapter::PlayL()
    {
    iMdaAudioToneUtility->Play();
    }
 
// CMdaAudioToneUtility is not able to record
void CToneAdapter::RecordL()
    {
    // No implementation required
}
 
// Stop the toneplay
void CToneAdapter::StopL()
    {
    iMdaAudioToneUtility->CancelPlay();
    }
 
// Identify mode
const TDesC& CToneAdapter::Identify()
    {
     return *itextResourceIdentifier;
    }
 
// Prepare to Complete
void CToneAdapter::MatoPrepareComplete( TInt /*aError*/ )
    {
    iMdaAudioToneUtility->SetVolume( iMdaAudioToneUtility->MaxVolume() );
}
 
// Play Complete
void CToneAdapter::MatoPlayComplete( TInt /*aError*/ )
    {
    // No implementation required
}
 
这个项目也体现了如何实现“动态菜单”,下面是和“动态菜单”相关的代码:
// This function is called by the EIKON framework just before it displays
// a menu pane. Its default implementation is empty, and by overriding it,
// the application can set the state of menu items dynamically according
// to the state of application data.
void CSoundAppUi::DynInitMenuPaneL( TInt aResourceId,
                                    CEikMenuPane* aMenuPane)
    {
    if ( aResourceId == R_SOUND_MENU )
        {
        iAudioAdapter->UpdateMenuL( aMenuPane );
        }
}
通过在AppUi中重写DynInitMenuPaneL()方法,然后在每次显示“菜单”之前,EIKON框架都会调用此方法,而此方法把“动态变化”的任务“委托”给各个播放类,从而实现了菜单的动态变化。
 
     CmdaAudioPlayerUtility
Description
Plays sampled audio data.
The class offers a simple interface to open, play and obtain information from, sampled audio data. The audio data can supplied either in a file, a descriptor or a URL (since version 7.0s).
While this class is abstract, the four static functions construct, initialise and return pointers to instances of concrete classes derived from this abstract class. This concrete class is part of the MMF implementation and is private.
从类的 Description 中可以看出,这个类是用来播放 audio data 的。
Audio data 可以是一个文件,也可以是一个描述符 (Descriptor) 或者是一个 URL
但是 URL 只使用于 7.0S 以后的版本 !
 
这个应该是我们在程序中用的最多的一个音频播放接口。
其对应的监听接口为 MmdaAudioPlayerCallback,作用和其它监听接口一样。
 
class CPlayerAdapter : public CBase,
                       public MAudioAdapter,
public MmdaAudioPlayerCallback
可以看出CPlayerAdapter和CtoneAdapter一样,实现了MaudioAdapter和自己响应的监听接口。
 
下面是它的具体实现
#include
#include
#include
 
#include "sound.pan"
#include "sound.hrh"
#include "playeradapter.h"
#include "soundappui.h"
 
CPlayerAdapter::CPlayerAdapter( CSoundAppUi& aAppUi )
: iState( ENotReady ), iAppUi( aAppUi )
    {
    // No implementation required
}
 
CPlayerAdapter* CPlayerAdapter::NewL( const TDesC& aFileName,
                                      CSoundAppUi& aAppUi )
    {
    CPlayerAdapter* self = NewLC( aFileName, aAppUi );
    CleanupStack::Pop( self ); 
    return self;
}
 
CPlayerAdapter* CPlayerAdapter::NewLC( const TDesC& aFileName,
                                       CSoundAppUi& aAppUi )
    {
    CPlayerAdapter* self = new ( ELeave ) CPlayerAdapter( aAppUi );
    CleanupStack::PushL( self );
    self->ConstructL( aFileName );
    return self;
}
 
void CPlayerAdapter::ConstructL( const TDesC& aFileName )
    {
 
     // Load a string from the resource file.
     // Identifying string for this audio utility.
     itextResourceIdentifier = CCoeEnv::Static()->AllocReadResourceL(
                                                            R_SOUN_MODE_PLAYER );
 
 
   #ifdef __WINS__
        // on emulator, the sound files used by application are
        // deployed onto c: drive
         _LIT( tFullPath,"c://system//apps//sound//" );
        TParse parse;
   
    #else
 
        // on real phone, application can be installed to the memory
        // card ( non-"C:" drive ),
        // this part of code evaluates current application path:
       
        // find the instance of EikonEnv
        CEikonEnv& ee = *CEikonEnv::Static();  
       
        // derive the instance of EikonAppUi
         CEikAppUi& ea = *( ee.EikAppUi() );    
 
        // fetch the application full filename
        TFileName tAppFullName = ea.Application()->AppFullName();
        TParse parse;
 
        // form parse object containing full app name
        parse.Set( tAppFullName, NULL, NULL );
       
        // get application path with drive letter
        TFileName tFullPath = parse.DriveAndPath();
 
    #endif
 
 
    // use tparse to get the full path to sound file
    parse.Set( tFullPath, &aFileName, NULL ); 
    TFileName tFullFileName = parse.FullName();
 
    // Create an audio player utility instance for playing
    // sample data from a file,
    // causes MMdaAudioPlayerCallback::MapcInitComplete to be called
    iMdaAudioPlayerUtility = CMdaAudioPlayerUtility::NewFilePlayerL( tFullFileName, *this );
}
 
CPlayerAdapter::~CPlayerAdapter()
    {
    delete iMdaAudioPlayerUtility;   
 
    // Delete private HBuf member for indetify
    delete itextResourceIdentifier;
}
 
// Update Menu
void CPlayerAdapter::UpdateMenuL( CEikMenuPane* aMenuPane )
    {
    aMenuPane->SetItemDimmed( ESoundCmdPlay,   ETrue );
    aMenuPane->SetItemDimmed( ESoundCmdRecord, ETrue );
    aMenuPane->SetItemDimmed( ESoundCmdStop,   ETrue );
    aMenuPane->SetItemDimmed( ESoundCmdChange, ETrue );
 
    switch ( iState )
        {
        case ENotReady:
            aMenuPane->SetItemDimmed( ESoundCmdChange, EFalse );
            break;
 
        case EReadyToPlay:
            aMenuPane->SetItemDimmed( ESoundCmdPlay, EFalse );
            aMenuPane->SetItemDimmed( ESoundCmdChange, EFalse );
            break;
 
        case EPlaying:
            aMenuPane->SetItemDimmed( ESoundCmdStop, EFalse );
            break;
 
        default:
            User::Panic( KPlayerAdapter, KSoundPanicInvalidMdaState );
            break;
        }
}
 
// Play the wav
void CPlayerAdapter::PlayL()
    {
    iMdaAudioPlayerUtility->Play();
    iState = EPlaying;
}
 
// Record the wav, not available in Player mode.
void CPlayerAdapter::RecordL()
    {
    // No implementation required
}
 
// Stop the play
void CPlayerAdapter::StopL()
    {
    iMdaAudioPlayerUtility->Stop();
    iState = EReadyToPlay;
}
 
// Identify mode
const TDesC& CPlayerAdapter::Identify()
    {
     return *itextResourceIdentifier;
}
 
// Mapc Init Complete
void CPlayerAdapter::MapcInitComplete( TInt aError,
                                 const TTimeIntervalMicroSeconds& /*aDuration*/ )
    {
    iState = aError ? ENotReady : EReadyToPlay;
}
 
// Mapc Play Complete
void CPlayerAdapter::MapcPlayComplete( TInt aError )
    {
    iState = aError ? ENotReady : EReadyToPlay;
    }
// End of File
 
    CmdaAudioRecorderUtility
Description
Plays back, records and edits audio sample data.
The class offers an interface to play, record and edit audio sample data. This data can be supplied either in a file or as a descriptor. The functions that start and stop playback and recording are defined in the base class CMdaAudioClipUtility.
While this class is abstract, the static NewL() function constructs, initialises and returns a pointer to an instance of a concrete class derived from this abstract class. This concrete class is part of the MMF implementation and is private.
这个是关于“录音”的音频接口,其原理和上面两个也一样,略去!
 

Trackback: http://tb.blog.youkuaiyun.com/TrackBack.aspx?PostId=1501283


基于粒子群优化算法的p-Hub选址优化(Matlab代码实现)内容概要:本文介绍了基于粒子群优化算法(PSO)的p-Hub选址优化问题的研究与实现,重点利用Matlab进行算法编程和仿真。p-Hub选址是物流与交通网络中的关键问题,旨在通过确定最优的枢纽节点位置和非枢纽节点的分配方式,最小化网络总成本。文章详细阐述了粒子群算法的基本原理及其在解决组合优化问题中的适应性改进,结合p-Hub中转网络的特点构建数学模型,并通过Matlab代码实现算法流程,包括初始化、适应度计算、粒子更新与收敛判断等环节。同时可能涉及对算法参数设置、收敛性能及不同规模案例的仿真结果分析,以验证方法的有效性和鲁棒性。; 适合人群:具备一定Matlab编程基础和优化算法理论知识的高校研究生、科研人员及从事物流网络规划、交通系统设计等相关领域的工程技术人员。; 使用场景及目标:①解决物流、航空、通信等网络中的枢纽选址与路径优化问题;②学习并掌握粒子群算法在复杂组合优化问题中的建模与实现方法;③为相关科研项目或实际工程应用提供算法支持与代码参考。; 阅读建议:建议读者结合Matlab代码逐段理解算法实现逻辑,重点关注目标函数建模、粒子编码方式及约束处理策略,并尝试调整参数或拓展模型以加深对算法性能的理解。
内容概要:本文全面介绍了C#全栈开发的学习路径与资源体系,涵盖从基础语法到企业级实战的完整知识链条。内容包括C#官方交互式教程、开发环境搭建(Visual Studio、VS Code、Mono等),以及针对不同应用场景(如控制台、桌面、Web后端、跨平台、游戏、AI)的进阶学习指南。通过多个实战案例——如Windows Forms记事本、WPF学生管理系统、.NET MAUI跨平台动物图鉴、ASP.NET Core实时聊天系统及Unity 3D游戏项目——帮助开发者掌握核心技术栈与架构设计。同时列举了Stack Overflow、Power BI、王者荣耀后端等企业级应用案例,展示C#在高性能场景下的实际运用,并提供了高星开源项目(如SignalR、AutoMapper、Dapper)、生态工具链及一站式学习资源包,助力系统化学习与工程实践。; 适合人群:具备一定编程基础,工作1-3年的研发人员,尤其是希望转型全栈或深耕C#技术栈的开发者; 使用场景及目标:①系统掌握C#在不同领域的应用技术栈;②通过真实项目理解分层架构、MVVM、实时通信、异步处理等核心设计思想;③对接企业级开发标准,提升工程能力和实战水平; 阅读建议:此资源以开发简化版Spring学习其原理和内核,不仅是代码编写实现也更注重内容上的需求分析和方案设计,所以在学习的过程要结合这些内容一起来实践,并调试对应的代码。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值