使用 Libgdx 文件句柄将 short[] 存储在文件中
Storing short[] in a file using Libgdx filehandle
我使用 libgdx AudioRecorder return short[] 录制了一些音频。我想我已将它转换为 byte[],这样它就可以存储在一个文件中,因为我需要音频能够随时播放。
这是我使用的一些变量:
final int samples = 44100;
boolean isMono = true;
final short[] data = new short[samples * 5];
final AudioRecorder recorder = Gdx.audio.newAudioRecorder(samples, isMono);
final AudioDevice player = Gdx.audio.newAudioDevice(samples, isMono);
这里我开始播放音频,我想我把 short[] 转换成了 byte[] ,如果我错了请纠正我。
public void startRecord(){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Record start:");
recorder.read(data, 0, data.length);
recorder.dispose();
ShortBuffer buffer = BufferUtils.newShortBuffer(2);
buffer.put(data[1]);
}
}).start();
}
public void playRecorded(){
new Thread(new Runnable() {
@Override
public void run() {
player.writeSamples(data, 0, data.length);
player.dispose();
}
}).start();
}
这是我之前如何存储 byte[] 的示例。但是我不能在这个方法上实现这个技术。请记住,我需要它成为一个 libgdx 解决方案。
public void onImagePicked(final InputStream stream) {
loading = "Loading";
pending = executor.submit(new AsyncTask<Pixmap>() {
@Override
public Pixmap call() throws Exception {
StreamUtils.copyStream(stream, file.write(false));
final byte[] bytes = file.readBytes();
final Pixmap pix = new Pixmap(bytes, 0, bytes.length);
return pix;
}
});
}
你好其实很简单。您可以像这样将字节数组转换为短数组:
// get all bytes
byte[] temp = ...
// create short with half the length (short = 2 bytes)
short[] data = new short[temp.length / 2];
// cast a byte array to short array
ByteBuffer.wrap(temp).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(data);
//data now has the short array in it
您可以像这样将短数组转换为字节:
// audio data
short[] data = ...;
//create a byte array to hold the data passed (short = 2 bytes)
byte[] temp = new byte[data.length * 2];
// cast a short array to byte array
ByteBuffer.wrap(temp).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(data);
// temp now has the byte array
示例项目
我在 github 中创建了一个示例项目,您可以克隆它以查看其工作原理。
示例项目 here
不过,如果您只是想快速浏览一下,这就是示例项目的游戏 class:
package com.leonziyo.recording;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.AudioDevice;
import com.badlogic.gdx.audio.AudioRecorder;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.utils.GdxRuntimeException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class MainGame extends ApplicationAdapter {
boolean recordTurn = true;
final int samples = 44100;
boolean isMono = true, recording = false, playing = false;
@Override
public void create () {}
@Override
public void render () {
/*Changing the color just to know when it is done recording or playing audio (optional)*/
if(recording)
Gdx.gl.glClearColor(1, 0, 0, 1);
else if(playing)
Gdx.gl.glClearColor(0, 1, 0, 1);
else
Gdx.gl.glClearColor(0, 0, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// We trigger recording and playing with touch for simplicity
if(Gdx.input.justTouched()) {
if(recordTurn)
recordToFile("sound.bin", 3); //pass file name and number of seconds to record
else
playFile("sound.bin"); //file name to play
recordTurn = !recordTurn;
}
}
@Override
public void dispose() {
}
private void recordToFile(final String filename, final int seconds) {
//Start a new thread to do the recording, because it will block and render won't be called if done in the main thread
new Thread(new Runnable() {
@Override
public void run() {
try {
recording = true;
short[] data = new short[samples * seconds];
AudioRecorder recorder = Gdx.audio.newAudioRecorder(samples, isMono);
recorder.read(data, 0, data.length);
recorder.dispose();
saveAudioToFile(data, filename);
}
catch(GdxRuntimeException e) {
Gdx.app.log("test", e.getMessage());
}
finally {
recording = false;
}
}
}).start();
}
private void playFile(final String filename) {
//Start a new thread to play the file, because it will block and render won't be called if done in the main thread
new Thread(new Runnable() {
@Override
public void run() {
try {
playing = true;
short[] data = getAudioDataFromFile(filename); //get audio data from file
AudioDevice device = Gdx.audio.newAudioDevice(samples, isMono);
device.writeSamples(data, 0, data.length);
device.dispose();
}
catch(GdxRuntimeException e) {
Gdx.app.log("test", e.getMessage());
}
finally {
playing = false;
}
}
}).start();
}
private short[] getAudioDataFromFile(String filename) {
FileHandle file = Gdx.files.local(filename);
byte[] temp = file.readBytes(); // get all bytes from file
short[] data = new short[temp.length / 2]; // create short with half the length (short = 2 bytes)
ByteBuffer.wrap(temp).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(data); // cast a byte array to short array
return data;
}
private void saveAudioToFile(short[] data, String filename) {
byte[] temp = new byte[data.length * 2]; //create a byte array to hold the data passed (short = 2 bytes)
ByteBuffer.wrap(temp).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(data); // cast a short array to byte array
FileHandle file = Gdx.files.local(filename);
file.writeBytes(temp, false); //save bytes to file
}
}
不要忘记添加权限以防写入外部存储和录音权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
我使用 libgdx AudioRecorder return short[] 录制了一些音频。我想我已将它转换为 byte[],这样它就可以存储在一个文件中,因为我需要音频能够随时播放。 这是我使用的一些变量:
final int samples = 44100;
boolean isMono = true;
final short[] data = new short[samples * 5];
final AudioRecorder recorder = Gdx.audio.newAudioRecorder(samples, isMono);
final AudioDevice player = Gdx.audio.newAudioDevice(samples, isMono);
这里我开始播放音频,我想我把 short[] 转换成了 byte[] ,如果我错了请纠正我。
public void startRecord(){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Record start:");
recorder.read(data, 0, data.length);
recorder.dispose();
ShortBuffer buffer = BufferUtils.newShortBuffer(2);
buffer.put(data[1]);
}
}).start();
}
public void playRecorded(){
new Thread(new Runnable() {
@Override
public void run() {
player.writeSamples(data, 0, data.length);
player.dispose();
}
}).start();
}
这是我之前如何存储 byte[] 的示例。但是我不能在这个方法上实现这个技术。请记住,我需要它成为一个 libgdx 解决方案。
public void onImagePicked(final InputStream stream) {
loading = "Loading";
pending = executor.submit(new AsyncTask<Pixmap>() {
@Override
public Pixmap call() throws Exception {
StreamUtils.copyStream(stream, file.write(false));
final byte[] bytes = file.readBytes();
final Pixmap pix = new Pixmap(bytes, 0, bytes.length);
return pix;
}
});
}
你好其实很简单。您可以像这样将字节数组转换为短数组:
// get all bytes
byte[] temp = ...
// create short with half the length (short = 2 bytes)
short[] data = new short[temp.length / 2];
// cast a byte array to short array
ByteBuffer.wrap(temp).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(data);
//data now has the short array in it
您可以像这样将短数组转换为字节:
// audio data
short[] data = ...;
//create a byte array to hold the data passed (short = 2 bytes)
byte[] temp = new byte[data.length * 2];
// cast a short array to byte array
ByteBuffer.wrap(temp).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(data);
// temp now has the byte array
示例项目
我在 github 中创建了一个示例项目,您可以克隆它以查看其工作原理。
示例项目 here
不过,如果您只是想快速浏览一下,这就是示例项目的游戏 class:
package com.leonziyo.recording;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.AudioDevice;
import com.badlogic.gdx.audio.AudioRecorder;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.utils.GdxRuntimeException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class MainGame extends ApplicationAdapter {
boolean recordTurn = true;
final int samples = 44100;
boolean isMono = true, recording = false, playing = false;
@Override
public void create () {}
@Override
public void render () {
/*Changing the color just to know when it is done recording or playing audio (optional)*/
if(recording)
Gdx.gl.glClearColor(1, 0, 0, 1);
else if(playing)
Gdx.gl.glClearColor(0, 1, 0, 1);
else
Gdx.gl.glClearColor(0, 0, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// We trigger recording and playing with touch for simplicity
if(Gdx.input.justTouched()) {
if(recordTurn)
recordToFile("sound.bin", 3); //pass file name and number of seconds to record
else
playFile("sound.bin"); //file name to play
recordTurn = !recordTurn;
}
}
@Override
public void dispose() {
}
private void recordToFile(final String filename, final int seconds) {
//Start a new thread to do the recording, because it will block and render won't be called if done in the main thread
new Thread(new Runnable() {
@Override
public void run() {
try {
recording = true;
short[] data = new short[samples * seconds];
AudioRecorder recorder = Gdx.audio.newAudioRecorder(samples, isMono);
recorder.read(data, 0, data.length);
recorder.dispose();
saveAudioToFile(data, filename);
}
catch(GdxRuntimeException e) {
Gdx.app.log("test", e.getMessage());
}
finally {
recording = false;
}
}
}).start();
}
private void playFile(final String filename) {
//Start a new thread to play the file, because it will block and render won't be called if done in the main thread
new Thread(new Runnable() {
@Override
public void run() {
try {
playing = true;
short[] data = getAudioDataFromFile(filename); //get audio data from file
AudioDevice device = Gdx.audio.newAudioDevice(samples, isMono);
device.writeSamples(data, 0, data.length);
device.dispose();
}
catch(GdxRuntimeException e) {
Gdx.app.log("test", e.getMessage());
}
finally {
playing = false;
}
}
}).start();
}
private short[] getAudioDataFromFile(String filename) {
FileHandle file = Gdx.files.local(filename);
byte[] temp = file.readBytes(); // get all bytes from file
short[] data = new short[temp.length / 2]; // create short with half the length (short = 2 bytes)
ByteBuffer.wrap(temp).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(data); // cast a byte array to short array
return data;
}
private void saveAudioToFile(short[] data, String filename) {
byte[] temp = new byte[data.length * 2]; //create a byte array to hold the data passed (short = 2 bytes)
ByteBuffer.wrap(temp).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(data); // cast a short array to byte array
FileHandle file = Gdx.files.local(filename);
file.writeBytes(temp, false); //save bytes to file
}
}
不要忘记添加权限以防写入外部存储和录音权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />