代码之家  ›  专栏  ›  技术社区  ›  Maksym Gontar

J2ME/BlackBerry-获取音频信号振幅级别?

  •  1
  • Maksym Gontar  · 技术社区  · 15 年前

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

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

    也见 Blackberry Audio Recording Sample Code
    How To - Record Audio on a BlackBerry smartphone

    谢谢您!

    2 回复  |  直到 9 年前
        1
  •  2
  •   Community Dai    7 年前

    获取原始PCM信号电平

    • 使用菜单和轨迹轮在图形中放大/缩小和左/右移动。
    • 音频格式:原始8000赫兹16位单声道PCM。
    • 在Bold 9000 RIM OS 4.6上测试
    • Algorythm应该在任何支持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;
        }
    }
    

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

    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

        2
  •  1
  •   Prabhu R    15 年前

    在大多数设备中,只支持具有单轨的中间格式。这是一种支持多个仪器在一个轨道上的MID0格式。我不确定API是否提供了测量信号振幅的工具。要将中间文件转换为可以使用的 Anvil Studio 有免费版和专业版

    要录制音频,您需要使用manager.createplayer(“capture://audio”)。另外,由于某些手机不支持PCM/AMR,因此将编码(PCM或AMR)保留在设备实现中。

    希望这有帮助!