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

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

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

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

谢谢!

【问题讨论】:

    标签: blackberry audio java-me core-audio pcm


    【解决方案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 processing
    SO - 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,这也可能会有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-31
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多