2

我想检测“口哨”的声音。为此,我实施了http://code.google.com/p/musicg/

源代码本身有问题。当您启动应用程序时,它已准备好收听,但是当您返回并再次重新启动检测器线程时,它不会触发哨声检测。

DetectorThread.java

package weetech.wallpaper.services;

import java.util.LinkedList;

import weetech.wallpaper.utils.Debug;
import android.media.AudioFormat;
import android.media.AudioRecord;

import com.musicg.api.WhistleApi;
import com.musicg.wave.WaveHeader;

public class DetectorThread extends Thread {

private RecorderThread recorder;
private WaveHeader waveHeader;
private WhistleApi whistleApi;
private Thread _thread;

private LinkedList<Boolean> whistleResultList = new LinkedList<Boolean>();
private int numWhistles;
private int totalWhistlesDetected = 0;
private int whistleCheckLength = 3;
private int whistlePassScore = 3;

public DetectorThread(RecorderThread recorder) {
    this.recorder = recorder;
    AudioRecord audioRecord = recorder.getAudioRecord();

    int bitsPerSample = 0;
    if (audioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) {
        bitsPerSample = 16;
    } else if (audioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_8BIT) {
        bitsPerSample = 8;
    }

    int channel = 0;
    // whistle detection only supports mono channel
    if (audioRecord.getChannelConfiguration() == AudioFormat.CHANNEL_IN_MONO) {
        channel = 1;
    }

    waveHeader = new WaveHeader();
    waveHeader.setChannels(channel);
    waveHeader.setBitsPerSample(bitsPerSample);
    waveHeader.setSampleRate(audioRecord.getSampleRate());
    whistleApi = new WhistleApi(waveHeader);
}

private void initBuffer() {
    numWhistles = 0;
    whistleResultList.clear();

    // init the first frames
    for (int i = 0; i < whistleCheckLength; i++) {
        whistleResultList.add(false);
    }
    // end init the first frames
}

public void start() {
    _thread = new Thread(this);
    _thread.start();
}

public void stopDetection() {
    _thread = null;
}

@Override
public void run() {
    Debug.e("", "DetectorThread started...");

    try {
        byte[] buffer;
        initBuffer();

        Thread thisThread = Thread.currentThread();
        while (_thread == thisThread) {
            // detect sound
            buffer = recorder.getFrameBytes();

            // audio analyst
            if (buffer != null) {
                // sound detected
                // MainActivity.whistleValue = numWhistles;

                // whistle detection
                // System.out.println("*Whistle:");

                try {
                    boolean isWhistle = whistleApi.isWhistle(buffer);
                    Debug.e("", "isWhistle : " + isWhistle + " "
                            + buffer.length);

                    if (whistleResultList.getFirst()) {
                        numWhistles--;
                    }

                    whistleResultList.removeFirst();
                    whistleResultList.add(isWhistle);

                    if (isWhistle) {
                        numWhistles++;
                    }

                    // Debug.e("", "numWhistles : " + numWhistles);

                    if (numWhistles >= whistlePassScore) {
                        // clear buffer
                        initBuffer();
                        totalWhistlesDetected++;

                        Debug.e("", "totalWhistlesDetected : "
                                + totalWhistlesDetected);

                        if (onWhistleListener != null) {
                            onWhistleListener.onWhistle();
                        }
                    }
                } catch (Exception e) {
                    Debug.w("", "" + e.getCause());
                }
                // end whistle detection
            } else {
                // Debug.e("", "no sound detected");
                // no sound detected
                if (whistleResultList.getFirst()) {
                    numWhistles--;
                }
                whistleResultList.removeFirst();
                whistleResultList.add(false);

                // MainActivity.whistleValue = numWhistles;
            }
            // end audio analyst
        }

        Debug.e("", "Terminating detector thread...");

    } catch (Exception e) {
        e.printStackTrace();
    }
}

private OnWhistleListener onWhistleListener;

public void setOnWhistleListener(OnWhistleListener onWhistleListener) {
    this.onWhistleListener = onWhistleListener;
}

public interface OnWhistleListener {
    void onWhistle();
}

public int getTotalWhistlesDetected() {
    return totalWhistlesDetected;
}
}

RecorderThread.java

public class RecorderThread {

private AudioRecord audioRecord;
private int channelConfiguration;
private int audioEncoding;
private int sampleRate;
private int frameByteSize; // for 1024 fft size (16bit sample size)
byte[] buffer;

public RecorderThread() {
    sampleRate = 44100;
    frameByteSize = 1024 * 2;

    channelConfiguration = AudioFormat.CHANNEL_IN_MONO;
    audioEncoding = AudioFormat.ENCODING_PCM_16BIT;

    int recBufSize = AudioRecord.getMinBufferSize(sampleRate,
            channelConfiguration, audioEncoding); // need to be larger than
                                                    // size of a frame
    audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
            sampleRate, channelConfiguration, audioEncoding, recBufSize);
    buffer = new byte[frameByteSize];
}

public AudioRecord getAudioRecord() {
    return audioRecord;
}

public boolean isRecording() {
    if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
        return true;
    }

    return false;
}

public void startRecording() {
    try {
        audioRecord.startRecording();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void stopRecording() {
    try {
        audioRecord.stop();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public byte[] getFrameBytes() {
    audioRecord.read(buffer, 0, frameByteSize);

    // analyze sound
    int totalAbsValue = 0;
    short sample = 0;
    float averageAbsValue = 0.0f;

    for (int i = 0; i < frameByteSize; i += 2) {
        sample = (short) ((buffer[i]) | buffer[i + 1] << 8);
        totalAbsValue += Math.abs(sample);
    }
    averageAbsValue = totalAbsValue / frameByteSize / 2;

    Debug.e("", "averageAbsValue : " + averageAbsValue);

    // no input
    if (averageAbsValue < 30) {
       return null;
    }

    return buffer;
}

}

用法

   public class DetectionService extends Service implements
    OnWhistleListener {

Handler handler;
private DetectorThread detectorThread;
private RecorderThread recorderThread;

@Override
public void onCreate() {
    super.onCreate();
    handler = new Handler();

}

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    try {
        if (intent != null && intent.getExtras() != null) {

            if (intent.getExtras().containsKey("action")) {
                Debug.e("", "action : " + intent.getStringExtra("action"));

                if (intent.getStringExtra("action").equals("start")) {
                    startWhistleDetection();
                }

                if (intent.getStringExtra("action").equals("stop")) {
                    stopWhistleDetection();
                    stopSelf();
                }
            }
        } else {

            startWhistleDetection();
            Debug.e("", "intent is null OR intent.getExtras() is null");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    return super.onStartCommand(intent, flags, startId);
}

private void startWhistleDetection() {

    try {
        stopWhistleDetection();
    } catch (Exception e) {
        e.printStackTrace();
    }

    recorderThread = new RecorderThread();
    recorderThread.startRecording();
    detectorThread = new DetectorThread(recorderThread);
    detectorThread.setOnWhistleListener(this);
    detectorThread.start();

}

private void stopWhistleDetection() {
    if (detectorThread != null) {
        detectorThread.stopDetection();
        detectorThread.setOnWhistleListener(null);
        detectorThread = null;
    }

    if (recorderThread != null) {
        recorderThread.stopRecording();
        recorderThread = null;
    }

}

@Override
public void onDestroy() {
    super.onDestroy();
}

@Override
public void onWhistle() {
    Debug.e("", "onWhistle()");
}

它会第一次检测到哨声,直到您不停止服务。但是在停止并再次启动后它没有检测到(不调用监听器)。我只是没有追踪,可能是什么问题?

录音有问题吗?

4

2 回答 2

6

我投入了 6 个小时,:D 难以置信,录音机停止时没有释放。停止后我刚刚释放了录音机。

源代码有轻微的愚蠢错误。它不是释放记录器。

public void stopRecording() {
    try {
        audioRecord.stop();
        audioRecord.release();

    } catch (Exception e) {
        e.printStackTrace();
    }
}
于 2013-02-08T10:26:56.290 回答
0

这段代码对我来说没问题

    if (detectorThread != null) {
            detectorThread.stopDetection();
            recorderThread.stopRecording();
    }
于 2015-06-04T09:45:13.157 回答