Symbian音频技术探究

本文详细解析了Symbian平台下的音频技术,包括播放音调、播放音频数据及录音编辑的方法。通过具体实例介绍了CMdaAudioToneUtility和CMdaAudioPlayerUtility等核心类的使用,并展示了动态菜单的实现。
 
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


当前,全球经济格局深刻调整,数字化浪潮席卷各行各业,智能物流作为现代物流发展的必然趋势和关键支撑,正迎来前所未有的发展机遇。以人工智能、物联网、大数据、云计算、区块链等前沿信息技术的快速迭代与深度融合为驱动,智能物流不再是传统物流的简单技术叠加,而是正在经历一场从自动化向智能化、从被动响应向主动预测、从信息孤岛向全面互联的深刻变革。展望2025年,智能物流系统将不再局限于提升效率、降低成本的基本目标,而是要构建一个感知更全面、决策更精准、执行更高效、协同更顺畅的智慧运行体系。这要求我们必须超越传统思维定式,以系统化、前瞻性的视角,全面规划和实施智能物流系统的建设。本实施方案正是基于对行业发展趋势的深刻洞察和对未来需求的精准把握而制定。我们的核心目标在于:通过构建一个集成了先进感知技术、大数据分析引擎、智能决策算法和高效协同平台的综合智能物流系统,实现物流全链路的可视化、透明化和智能化管理。这不仅是技术层面的革新,更是管理模式和服务能力的全面提升。本方案旨在明确系统建设的战略方向、关键任务、技术路径和实施步骤,确保通过系统化部署,有效应对日益复杂的供应链环境,提升整体物流韧性,优化资源配置效率,降低运营成本,并最终为客户创造更卓越的价值体验。我们致力于通过本方案的实施,引领智能物流迈向更高水平,为构建现代化经济体系、推动高质量发展提供强有力的物流保障。
电源题电赛单相并网离网软件硬件锁相环单极性双极性调制等代码及仿真环路计算资料+原理图PCB内容概要:本文档是一份关于电力电子与能源系统仿真研究的技术资料集合,涵盖单相并网/离网系统、软件与硬件锁相环设计、单极性与双极性调制技术、虚拟同步机控制建模、P2G-CCS耦合系统、微电网优化调度、光伏风电联合运行、储能配置及需求响应等多个电力系统核心主题。文档提供了大量基于Matlab/Simulink的代码实现与仿真模型,包括LLC谐振变换器小信号分析、永磁同步电机控制、DC-AC变换器设计、光伏阵列故障仿真、直流微电网建模等,并附有原理图与PCB设计资源。同时整合了智能优化算法(如遗传算法、粒子群、灰狼优化器)、机器学习模型(如LSTM、CNN-GRU-Attention)在负荷预测、故障诊断、路径规划等领域的应用案例,形成一个跨学科的科研资源包。; 适合人群:电气工程、自动化、能源系统及相关专业的研究生、科研人员以及从事电力电子、微电网、新能源控制方向的工程师;具备Matlab/Simulink编程基础和一定电力系统理论知识者更佳。; 使用场景及目标:① 支持电赛或科研项目中对并网逆变器、锁相环、调制策略的设计与验证;② 用于复现高水平论文(如EI/SCI)中的优化调度、控制算法与仿真模型;③ 辅助开展微电网能量管理、储能配置、需求响应策略等课题的研究与代码开发;④ 提供可直接调用的算法模板与仿真平台,提升科研效率。; 阅读建议:建议按照文档结构逐步浏览,优先下载并整理网盘中的完整资源包,结合具体研究方向选取对应代码与模型进行调试与二次开发;对于复杂算法(如NSGA-II、ADMM、MPC),应配合文献理解其数学原理后再实施仿真;关注其中“论文复现”类内容以提升学术研究规范性与技术深度。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值