使用 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" />