问题
Is it possible in j2me to measure signal amplitude of audio record made by JSR-135 Player?
I know I can access buffer, but then what?
Target model Bold 9000, supported formats PCM and AMR. Which format I should use?
See also
Blackberry Audio Recording Sample Code
How To - Record Audio on a BlackBerry smartphone
Thank you!
回答1:
Get raw PCM signal level
- Use menu and trackwheel to zoom in/out and move left/right within graph.
- Audio format: raw 8000 Hz 16 bit mono pcm.
- Tested on Bold 9000 RIM OS 4.6
- Algorythm should work in any mobile, where j2me and pcm is supported, of course implementation may require changes.
Using thread for audio recording:
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;
}
}
And method for painting graph using byte[] buffer:
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;
}
Screen class:
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);
}
}
Was helpfull:
ADC -> integer PCM file -> signal processing
SO - How is audio represented with numbers?
Convert byte array to integer
回答2:
In most devices, only MID format with a single track is supported. That is the mid0 format that supports multiple instruments in one single track. I am not sure if the api provides the facility to measure the amplitude of a signal. To convert mid files to you can use Anvil Studio that has both free and pro versions
To record audio you need to use Manager.createPlayer("capture://audio"). Also leave the encoding (PCM or AMR) to the device implementation because some phones don't support PCM/AMR
Hope this helps!
来源:https://stackoverflow.com/questions/1497706/j2me-blackberry-get-audio-signal-amplitude-level