J2ME/Blackberry - 获取音频信号幅度级别?

Posted

技术标签:

【中文标题】J2ME/Blackberry - 获取音频信号幅度级别?【英文标题】:J2ME/Blackberry - get audio signal amplitude level? 【发布时间】:2009-09-30 12:05:03 【问题描述】:

在 j2me 中是否可以测量 JSR-135 播放器制作的音频记录的信号幅度? 我知道我可以访问缓冲区,但是然后呢?

目标型号 Bold 9000,支持格式 PCM 和 AMR。我应该使用哪种格式?

另请参阅 Blackberry Audio Recording Sample CodeHow To - Record Audio on a BlackBerry smartphone

谢谢!

【问题讨论】:

【参考方案1】:

获取原始 PCM 信号电平

使用菜单和拨轮在图形内放大/缩小和左/右移动。 音频格式:原始 8000 Hz 16 位单声道 pcm。 在 Bold 9000 RIM OS 4.6 上测试 算法应该适用于任何支持 j2me 和 pcm 的移动设备,当然实现可能需要更改。

使用线程进行录音:

class VoiceNotesRecorderThread extends Thread 

    private Player _player;
    private RecordControl _rcontrol;
    private ByteArrayOutputStream _output;
    private byte _data[];

    VoiceNotesRecorderThread() 
    

    public void run() 
        try 
            _player = Manager
                .createPlayer("capture://audio?encoding=audio/basic");
            _player.realize();
            _rcontrol = (RecordControl) _player
                .getControl("RecordControl");
            _output = new ByteArrayOutputStream();
            _rcontrol.setRecordStream(_output);
            _rcontrol.startRecord();
            _player.start();
         catch (final Exception e) 
            UiApplication.getUiApplication().invokeAndWait(new Runnable() 
                public void run() 
                    Dialog.inform(e.toString());
                
            );
        
    

    public void stop() 
        try 
            _rcontrol.commit();
            _data = _output.toByteArray();
            _output.close();
            _player.close();
         catch (Exception e) 
            synchronized (UiApplication.getEventLock()) 
                Dialog.inform(e.toString());
            
        
    

    byte[] getData() 
        return _data;
    

以及使用byte[]缓冲区绘制图形的方法:

private Bitmap getGraph(byte[] buffer, int zoom, int startFrom) 
    Bitmap result = new Bitmap(Display.getWidth(), Display.getHeight());
    Graphics g = new Graphics(result);
    g.setColor(Color.BLACK);
    int xPos = 0;
    int yPos = Display.getHeight() >> 1;
    for (int i = startFrom; i < buffer.length; i += 2 * zoom) 
        byte[] b = new byte[]  buffer[i], buffer[i + 1] ;
        int level = (signedShortToInt(b) * 100 / 32767);
        if (100 < level) 
            level -= 200;
        

        g.drawPoint(xPos, yPos - level);
        xPos++;
    
    return result;


public static final int signedShortToInt(byte[] b) 
    int result = (b[0] & 0xff) | (b[1] & 0xff) << 8;
    return result;

屏幕类:

class Scr extends MainScreen 
    BitmapField mGraphField = new BitmapField(new Bitmap(Display.getWidth(),
            Display.getHeight()));

    private VoiceNotesRecorderThread m_thread;

    public Scr() 
        add(mGraphField);
        add(new NullField(FOCUSABLE));
    

    boolean mRecording = false;
    private int mZoom = 1;
    private int mStartFrom = 0;

    byte[] mAudioData = null;

    protected void makeMenu(Menu menu, int instance) 
        super.makeMenu(menu, instance);
        menu.add(mRecordStopMenuItem);

        menu.add(mPaintZoomIn);
        menu.add(mPaintZoomOut);
        menu.add(mPaintZoomToFitScreen);

        menu.add(mPaintMoveRight);
        menu.add(mPaintMoveLeft);
        menu.add(mPaintMoveToBegin);
    

    MenuItem mRecordStopMenuItem = new MenuItem("Record", 0, 0) 
        public void run() 
            if (!mRecording) 
                m_thread = new VoiceNotesRecorderThread();
                m_thread.start();
                mRecording = true;
                this.setText("Stop");
             else 
                m_thread.stop();
                mAudioData = m_thread.getData();
                zoomToFitScreen();
                mRecording = false;
                this.setText("Record");
            
        
    ;

    MenuItem mPaintZoomIn = new MenuItem("Zoom In", 0, 0) 
        public void run() 
            zoomIn();
        
    ;

    MenuItem mPaintZoomOut = new MenuItem("Zoom Out", 0, 0) 
        public void run() 
            zoomOut();
        
    ;

    MenuItem mPaintZoomToFitScreen = new MenuItem("Fit Screen", 0, 0) 
        public void run() 
            zoomToFitScreen();
        
    ;

    MenuItem mPaintMoveLeft = new MenuItem("Left", 0, 0) 
        public void run() 
            moveLeft();
        
    ;

    MenuItem mPaintMoveRight = new MenuItem("Right", 0, 0) 
        public void run() 
            moveRight();
        
    ;

    MenuItem mPaintMoveToBegin = new MenuItem("To Begin", 0, 0) 
        public void run() 
            moveToBegin();
        
    ;

    private void zoomOut() 
        if (mZoom < 200)
            mZoom++;
        mGraphField.setBitmap(getGraph(mAudioData, mZoom, mStartFrom));
    

    private void zoomIn() 
        if (mZoom > 1)
            mZoom--;
        mGraphField.setBitmap(getGraph(mAudioData, mZoom, mStartFrom));
    

    private void zoomToFitScreen() 
        int lenght = mAudioData.length;
        mZoom = (lenght / 2) / Display.getWidth();
        mGraphField.setBitmap(getGraph(mAudioData, mZoom, mStartFrom));
    

    private void moveRight() 
        if (mStartFrom < mAudioData.length - 30)
            mStartFrom += 30;
        mGraphField.setBitmap(getGraph(mAudioData, mZoom, mStartFrom));
    

    private void moveLeft() 
        if (mStartFrom > 30)
            mStartFrom -= 30;
        mGraphField.setBitmap(getGraph(mAudioData, mZoom, mStartFrom));
    

    private void moveToBegin() 
        mStartFrom = 0;
        mGraphField.setBitmap(getGraph(mAudioData, mZoom, mStartFrom));
    

    protected boolean navigationMovement(int dx, int dy, int status, 
        int time) 

        if (dx < 0) 
            moveLeft();
         else if (dx > 0) 
            moveRight();
        
        if (dy < 0) 
            zoomIn();
         else if (dy > 0) 
            zoomOut();
        
        return super.navigationMovement(dx, dy, status, time);
    

很有帮助:ADC -> integer PCM file -> signal processingSO - How is audio represented with numbers?Convert byte array to integer

【讨论】:

我不得不从您的帖子中删除图片,因为 ImageShack 已将其删除并替换为广告。请参阅meta.stackexchange.com/q/263771/215468 了解更多信息。如果可能,您最好重新上传它们。谢谢!【参考方案2】:

在大多数设备中,仅支持具有单个轨道的 MID 格式。那是在一个轨道中支持多种乐器的 mid0 格式。我不确定 api 是否提供了测量信号幅度的工具。要将 mid 文件转换为您可以使用具有免费和专业版本的Anvil Studio

要录制音频,您需要使用 Manager.createPlayer("capture://audio")。还要将编码(PCM 或 AMR)留给设备实现,因为某些手机不支持 PCM/AMR

希望这会有所帮助!

【讨论】:

谢谢 Ram,我需要录制音频并从中测量信号电平,不能使用这种方法。但我会检查 midi,这也可能会有所帮助。

以上是关于J2ME/Blackberry - 获取音频信号幅度级别?的主要内容,如果未能解决你的问题,请参考以下文章

将 Java 代码 1.5 降级到 1.4(奖励积分:J2ME、Blackberry !!!)

基于matlab的声音信号采集与处理

简述pcm数字化音频的主要原理

matlab怎么将音频信号的幅值限定在

CoreAudio/OpenAL:如何获取传出的音频信号

如何实时获取特定频率音频信号的幅度android