从麦克风流,添加效果并使用tarsos android库保存到wav文件 [英] stream from microphone, add effect and save to wav file using tarsos android library

查看:152
本文介绍了从麦克风流,添加效果并使用tarsos android库保存到wav文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:我正在使用android studio,当前正在使用最新的 tarsos音频库应该与android兼容,并且实际上已经成功地将该库添加到了我的android studio项目中.我以前尝试使用JTransforms和Minim库没有任何运气. 编辑于8/23/17:发现并修复了一些错误,重新发布了当前代码,但仍未解决以下总结的实际问题:

Notes: I'm using android studio and currently I'm using the latest tarsos audio library that is supposed to be compatible with android, and in fact have successfully added the library to my android studio project. I previously tried using the JTransforms and the Minim libraries with no luck. EDITED 8/23/17: found and fixed some bugs, reposted current code, still made no progress with the actual problem summarized below:

总结:在我发布的第5个代码块中,第15行被注释掉了,我需要知道如何使该行正常工作而不抛出编译错误

Summary: in the 5th code block I have posted, on line 15 that is commented out, I need to know how to get that line to work and not throw a compile error

我想做的是从麦克风录制,并且在录制时使用tarsos库中的dsp BandPass过滤器并将结果输出到.wav文件.我可以在该教程具有,我知道我丢失了某些东西和/或做错了什么,但是我已经将其搜索了将近一个星期,并且没有找到有效的解决方案,我只找到了指向库中的Java文件的链接,没有帮助,因为我找不到有关如何正确使用它们的教程.我究竟做错了什么?这是我要使用的tarsos方法的相关代码:

What I'm trying to do is record from the microphone, and while recording use the dsp BandPass filter from the tarsos library and output the results to a .wav file. I can successfully stream the microphone to a .wav file following this tutorial by using the android.media imports, but that doesn't allow me to add the BandPass filter, and using the tarsos imports functions don't allow me to use the save as .wav methods that that tutorial has, I know I'm missing something and/or doing something wrong, but I've been googling this for almost a week and haven't found a working solution, I've only found links to the java files that are inside the library which isn't helpful as I couldn't find tutorials on how to correctly use them. What am I doing wrong? Here is the relevant code for the tarsos method I'm trying to use:

相关的导入和全局"变量

the related imports and 'global' variables

import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.media.AudioFormat;
import android.media.AudioTrack;

import be.tarsos.dsp.AudioDispatcher;
import be.tarsos.dsp.AudioProcessor;
import be.tarsos.dsp.filters.BandPass;
import be.tarsos.dsp.io.android.AudioDispatcherFactory;

//start the class 

AudioRecord alteredRecord = null;
AudioDispatcher dispatcher;
float freqChange;
float tollerance;
private static final int RECORDER_BPP = 16;
private static final String AUDIO_RECORDER_FOLDER = "Crowd_Speech";
private static final String AUDIO_RECORDER_TEMP_FILE = "record_temp.raw";
private static final int RECORDER_SAMPLERATE = 44100;
private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private int bufferSize = 1024;
private Thread recordingThread = null;

//set the min buffer size in onCreate event
bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, 
RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING)*4;

这将开始在onClick方法中进行麦克风录音,并且通过注释/取消注释2个正在运行"的变量值之一,我可以在调用startRecording方法时在过滤器或不过滤器(android或tarsos函数)之间切换

This starts the mic recording inside an onClick method, and by commenting/uncommenting one of the 2 'running' variable values I can switch between filter or no filter (android or tarsos functions) when the startRecording method is called

if(crowdFilter && running==0 && set==0){//crowd speech mode, start talking
    Icons(2,"");
    running=4;//start recording from mic, apply bandpass filter and save as wave file using TARSOS import
    //running=5;//start recording from mic, no filter, save as wav file using android media import
    freqChange = Globals.minFr[Globals.curUser];
    tollerance = 40;
    set=1;
    startRecording();
}

开始录制方法:

private void startRecording() {

    if (running == 5) {//start recording from mic, no filter, save as wav file using android media library
        alteredRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, RECORDER_SAMPLERATE, RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING, bufferSize);
            alteredRecord.startRecording();
            isRecording = true;
            recordingThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    writeAudioDataToFile();
                }
            }, "Crowd_Speech Thread");
            recordingThread.start();
    }

    if (running == 4) {//start recording from mic, apply bandpass filter and save as wave file using TARSOS library
        dispatcher = AudioDispatcherFactory.fromDefaultMicrophone(RECORDER_SAMPLERATE, bufferSize, 0);
        AudioProcessor p = new BandPass(freqChange, tollerance, RECORDER_SAMPLERATE);
        dispatcher.addAudioProcessor(p);
            isRecording = true;
            dispatcher.run();
            recordingThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    writeAudioDataToFile();
                }
            }, "Crowd_Speech Thread");
            recordingThread.start();
    }
}

onClick方法中的停止录制按钮

Stop recording button inside an onClick method

if(crowdFilter && (running==4 || running==5) && set==0) {//crowd speech finished talking
    Icons(1, "");
    stopRecording();
    set = 1;
}

在这之前,两种情况都很好,如果运行== 4(应用了tarsos dsp过滤器),程序将崩溃.如果我使用running == 5(没有过滤器的android.media方式),则其余全部工作正常并保存文件,但未应用BandPass效果.如果我尝试用tarsos调度程序= AudioDispatcherFactory ...(例如,调度程序=新的AudioRecord ...)换出alteredRecord = new AudioRecord ...,则它们是不兼容的,甚至不会考虑编译. (这就是为什么以下方法的第15行被注释掉了的原因)

Both cases are fine until this point, if running==4 (tarsos dsp filter applied) the program crashes. if I use running==5 (the android.media way with no filter) the whole rest of this works fine and saves the file, but no BandPass effect applied. if I try swapping out the alteredRecord = new AudioRecord... with the tarsos dispatcher = AudioDispatcherFactory... ( such as dispatcher = new AudioRecord...) they are incompatible and will not even think of compiling. (That's why line 15 in the following method is commented out)

private void writeAudioDataToFile(){
    byte data[] = new byte[bufferSize];
    String filename = getTempFilename();
    FileOutputStream os = null;
    try {
        os = new FileOutputStream(filename);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    int read = 0;
    if(null != os){
        while(isRecording){
            if(running==4)
            {
                //read = dispatcher.(data, 0, bufferSize);
            }
            if(running==5)
            {
                read = alteredRecord.read(data, 0, bufferSize);
            }
            if(AudioRecord.ERROR_INVALID_OPERATION != read){
                try {
                    os.write(data);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        try {
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

private void stopRecording(){
    if(null != alteredRecord) {
        isRecording = false;
        int i = alteredRecord.getState();
        if (i == 1) {
            running = 0;
            alteredRecord.stop();
            alteredRecord.release();
            alteredRecord = null;
            recordingThread = null;
        }
    }
        if(null !=dispatcher){
            isRecording = false;
            running = 0;
            dispatcher.stop();
            recordingThread = null;
        }
    copyWaveFile(getTempFilename(),getFilename());
    deleteTempFile();
}

private void deleteTempFile() {
    File file = new File(getTempFilename());
    file.delete();
}

private void copyWaveFile(String inFilename,String outFilename){
    FileInputStream in = null;
    FileOutputStream out = null;
    long totalAudioLen = 0;
    long totalDataLen = totalAudioLen + 36;
    long longSampleRate = RECORDER_SAMPLERATE;
    int channels = 1;
    long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels/8;
    byte[] data = new byte[bufferSize];
    try {
        in = new FileInputStream(inFilename);
        out = new FileOutputStream(outFilename);
        totalAudioLen = in.getChannel().size();
        totalDataLen = totalAudioLen + 36;
        WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
                longSampleRate, channels, byteRate);
        while(in.read(data) != -1){
            out.write(data);
        }
        in.close();
        out.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void WriteWaveFileHeader(
        FileOutputStream out, long totalAudioLen,
        long totalDataLen, long longSampleRate, int channels,
        long byteRate) throws IOException {
    byte[] header = new byte[44];
    header[0] = 'R';header[1] = 'I'; header[2] = 'F';header[3] = 'F';// RIFF/WAVE header
    header[4] = (byte) (totalDataLen & 0xff);
    header[5] = (byte) ((totalDataLen >> 8) & 0xff);
    header[6] = (byte) ((totalDataLen >> 16) & 0xff);
    header[7] = (byte) ((totalDataLen >> 24) & 0xff);
    header[8] = 'W';header[9] = 'A';header[10] = 'V';header[11] = 'E';header[12] = 'f';header[13] = 'm';header[14] = 't';header[15] = ' ';// 'fmt ' chunk
    header[16] = 16;header[17] = 0;header[18] = 0;header[19] = 0;// 4 bytes: size of 'fmt ' chunk
    header[20] = 1;header[21] = 0;header[22] = (byte) channels;header[23] = 0;// format = 1
    header[24] = (byte) (longSampleRate & 0xff);header[25] = (byte) ((longSampleRate >> 8) & 0xff);header[26] = (byte) ((longSampleRate >> 16) & 0xff);
    header[27] = (byte) ((longSampleRate >> 24) & 0xff);header[28] = (byte) (byteRate & 0xff);header[29] = (byte) ((byteRate >> 8) & 0xff);
    header[30] = (byte) ((byteRate >> 16) & 0xff); header[31] = (byte) ((byteRate >> 24) & 0xff);
    header[32] = (byte) (2 * 16 / 8);header[33] = 0;// block align
    header[34] = RECORDER_BPP;header[35] = 0;header[36] = 'd';header[37] = 'a';header[38] = 't';header[39] = 'a';
    header[40] = (byte) (totalAudioLen & 0xff);header[41] = (byte) ((totalAudioLen >> 8) & 0xff);header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
    header[43] = (byte) ((totalAudioLen >> 24) & 0xff);// bits per sample
    out.write(header, 0, 44);
}

推荐答案

已解决,您需要使用writer函数,而无需使用从android.media导入函数保存wav文件所需的任何方法,是我更改的startRecording方法中的工作代码段:

Solved, you need to use the writer function, and not bother with any of the methods needed to save a wav file from the android.media import functions, this is the working code segment from the startRecording method I changed:

if (running == 4) {//start recording from mic, apply bandpass filter and save as wave file using TARSOS library
        dispatcher = AudioDispatcherFactory.fromDefaultMicrophone(RECORDER_SAMPLERATE, bufferSize, 0);
        AudioProcessor p = new BandPass(freqChange, tollerance, RECORDER_SAMPLERATE);
        dispatcher.addAudioProcessor(p);
        isRecording = true;
        // Output
        RandomAccessFile outputFile = new RandomAccessFile(getFilename(), "rw");
        TarsosDSPAudioFormat outputFormat = new TarsosDSPAudioFormat(44100, 16, 1, true, false);
        WriterProcessor writer = new WriterProcessor(outputFormat, outputFile);
        dispatcher.addAudioProcessor(writer);
        recordingThread = new Thread(new Runnable() {
            @Override
            public void run() {
                dispatcher.run();
            }
        }, "Crowd_Speech Thread");
        recordingThread.start();
    }

这篇关于从麦克风流,添加效果并使用tarsos android库保存到wav文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆