麦克风输入的处理

发布于 2024-11-29 22:08:11 字数 5594 浏览 5 评论 0 原文

我正在尝试从麦克风获取音频数据。我通过使用 AudioRecord 类实现了这一点,该类用类型 Shorts 填充缓冲区。

最终我想绘制该缓冲区的图表,以便获得类似示波器的显示(实时信息)。问题是,如果我想显示一个值(比如以文本形式),那么我需要一个不同的线程来更新 UI。目前,我通过使用 AsyncTask 并使用 AsyncTasks.publishProgress() 更新 UI 来完成此操作。到目前为止,我还不是很成功,想知道我是否走在正确的道路上?手柄是更好的方法吗?有没有人以前做过类似的事情,如果有的话什么方法对你有用?另外,是否可以简单地轮询麦克风?


这是我的代码。它旨在输出来自 MIC 的每个读取样本。它似乎以可接受的速率执行此操作,但偶尔会显示零。为什么?

package com.ss.audioacquireapp3;

import android.app.Activity;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;


public class AudioAcquireApp3Activity extends Activity 
{
        //Properties (AsyncTask)
        protected TextView _percentField;
        protected InitTask _initTask;

        //Properties (MIC)
        public AudioRecord audioRecord; 
        public int mSamplesRead; //how many samples read 
        public int recordingState;
        public int buffersizebytes; 
        public int channelConfiguration = AudioFormat.CHANNEL_IN_MONO; 
        public int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; 
        public static short[] buffer; //+-32767 
        public static final int SAMPPERSEC = 44100; //samp per sec 8000, 11025, 22050 44100 or 48000

    @Override
    public void onCreate( Bundle savedInstanceState ) 
    {
        super.onCreate(savedInstanceState);
        setContentView( R.layout.main );

        _percentField = ( TextView ) findViewById( R.id.percent_field );

        buffersizebytes = AudioRecord.getMinBufferSize(SAMPPERSEC,channelConfiguration,audioEncoding); //4096 on ion 
        buffer = new short[buffersizebytes]; 
        audioRecord = new AudioRecord(android.media.MediaRecorder.AudioSource.MIC,SAMPPERSEC,channelConfiguration,audioEncoding,buffersizebytes); //constructor 

        _initTask = new InitTask();
        _initTask.execute( this );
    }

    /**
     * sub-class of AsyncTask
     */
    protected class InitTask extends AsyncTask<Context, Integer, String>
    {
        // -- run intensive processes here
        // -- notice that the datatype of the first param in the class definition matches the param passed to this method 
        // -- and that the datatype of the last param in the class definition matches the return type of this method
                @Override
                protected String doInBackground( Context... params ) 
                {
                        //-- on every iteration
                        //-- runs a while loop that causes the thread to sleep for 50 milliseconds 
                        //-- publishes the progress - calls the onProgressUpdate handler defined below
                        //-- and increments the counter variable i by one
                        //int i = 0;

                    audioRecord.startRecording();

                        while( true ) 
                        {
                                try{
                                        mSamplesRead = audioRecord.read(buffer, 0, buffersizebytes);

                                        int amp;

                                        for(int i = 0; i < buffersizebytes - 1; i++){
                                            amp = (int)buffer[i];
                                            publishProgress( amp );
                                        }

                                } catch( Exception e ){                        
                                }
                        }
                }

                // -- gets called just before thread begins
                @Override
                protected void onPreExecute() 
                {
                        //Log.i( "makemachine", "onPreExecute()" );
                        super.onPreExecute();

                }

                // -- called from the publish progress 
                // -- notice that the datatype of the second param gets passed to this method
                @Override
                protected void onProgressUpdate(Integer... values) 
                {
                        super.onProgressUpdate(values);
                        //Log.i( "makemachine", "onProgressUpdate(): " +  String.valueOf( values[0] ) );
                        _percentField.setText( String.valueOf(values[0]) );
                }

                // -- called as soon as doInBackground method completes
                // -- notice that the third param gets passed to this method
                @Override
                protected void onPostExecute( String result ) 
                {
                        super.onPostExecute(result);
                        //Log.i( "makemachine", "onPostExecute(): " + result );
                }   


     } 
}

这里是 main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center_vertical|center_horizontal"
    >

<TextView android:id="@+id/percent_field"
          android:layout_width="fill_parent" 
          android:layout_height="wrap_content"
          android:gravity="center_horizontal"/>

</LinearLayout>

请注意,您需要将其添加到 AndroidManifest.xml

<uses-permission android:name="android.permission.RECORD_AUDIO" />

我在 LG Optimus Black 上运行它。请帮助我使这段代码尽可能高效。

I am trying to get audio data from the microphone. I have achieved this by using the AudioRecord class which fills a buffer with type shorts.

Eventually I would like to graph this buffer so that I get an oscilloscope like display (realtime information). The problem is that if I want to display a value (say in text) then I need a different thread to update the UI. Currently I'm doing this by using an AsyncTask and updating the UI with AsyncTasks.publishProgress(). So far I haven't been very successful and would like to know if I'm on the right track? Are handles a better way to go? Is there anyone out there who has done something similar before, and if so what method worked for you? Also, is it at all possible to simply poll the microphone?


Here is my code. It is meant to output every read sample from the MIC. It appears to do this at an acceptable rate but occasionally displays a zero. Why?

package com.ss.audioacquireapp3;

import android.app.Activity;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;


public class AudioAcquireApp3Activity extends Activity 
{
        //Properties (AsyncTask)
        protected TextView _percentField;
        protected InitTask _initTask;

        //Properties (MIC)
        public AudioRecord audioRecord; 
        public int mSamplesRead; //how many samples read 
        public int recordingState;
        public int buffersizebytes; 
        public int channelConfiguration = AudioFormat.CHANNEL_IN_MONO; 
        public int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; 
        public static short[] buffer; //+-32767 
        public static final int SAMPPERSEC = 44100; //samp per sec 8000, 11025, 22050 44100 or 48000

    @Override
    public void onCreate( Bundle savedInstanceState ) 
    {
        super.onCreate(savedInstanceState);
        setContentView( R.layout.main );

        _percentField = ( TextView ) findViewById( R.id.percent_field );

        buffersizebytes = AudioRecord.getMinBufferSize(SAMPPERSEC,channelConfiguration,audioEncoding); //4096 on ion 
        buffer = new short[buffersizebytes]; 
        audioRecord = new AudioRecord(android.media.MediaRecorder.AudioSource.MIC,SAMPPERSEC,channelConfiguration,audioEncoding,buffersizebytes); //constructor 

        _initTask = new InitTask();
        _initTask.execute( this );
    }

    /**
     * sub-class of AsyncTask
     */
    protected class InitTask extends AsyncTask<Context, Integer, String>
    {
        // -- run intensive processes here
        // -- notice that the datatype of the first param in the class definition matches the param passed to this method 
        // -- and that the datatype of the last param in the class definition matches the return type of this method
                @Override
                protected String doInBackground( Context... params ) 
                {
                        //-- on every iteration
                        //-- runs a while loop that causes the thread to sleep for 50 milliseconds 
                        //-- publishes the progress - calls the onProgressUpdate handler defined below
                        //-- and increments the counter variable i by one
                        //int i = 0;

                    audioRecord.startRecording();

                        while( true ) 
                        {
                                try{
                                        mSamplesRead = audioRecord.read(buffer, 0, buffersizebytes);

                                        int amp;

                                        for(int i = 0; i < buffersizebytes - 1; i++){
                                            amp = (int)buffer[i];
                                            publishProgress( amp );
                                        }

                                } catch( Exception e ){                        
                                }
                        }
                }

                // -- gets called just before thread begins
                @Override
                protected void onPreExecute() 
                {
                        //Log.i( "makemachine", "onPreExecute()" );
                        super.onPreExecute();

                }

                // -- called from the publish progress 
                // -- notice that the datatype of the second param gets passed to this method
                @Override
                protected void onProgressUpdate(Integer... values) 
                {
                        super.onProgressUpdate(values);
                        //Log.i( "makemachine", "onProgressUpdate(): " +  String.valueOf( values[0] ) );
                        _percentField.setText( String.valueOf(values[0]) );
                }

                // -- called as soon as doInBackground method completes
                // -- notice that the third param gets passed to this method
                @Override
                protected void onPostExecute( String result ) 
                {
                        super.onPostExecute(result);
                        //Log.i( "makemachine", "onPostExecute(): " + result );
                }   


     } 
}

And here is main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center_vertical|center_horizontal"
    >

<TextView android:id="@+id/percent_field"
          android:layout_width="fill_parent" 
          android:layout_height="wrap_content"
          android:gravity="center_horizontal"/>

</LinearLayout>

Note that you need to add this to AndroidManifest.xml

<uses-permission android:name="android.permission.RECORD_AUDIO" />

I am running this on a LG Optimus Black. Please help me make this code as efficient as possible.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不离久伴 2024-12-06 22:08:12
  1. 如果您需要从任何线程更新 UI 线程,您可以始终使用 Activity.runOnUiThread(Runnable action)。有关详细信息,请参阅 Activity 类 javadoc。
  2. 我不确定“简单轮询麦克风”到底是什么意思,但在我看来,在录制麦克风时,AudioRecord 是一个很好的方法。以下是示例实现的链接,该示例实现实时读取录制音频的频率:http://www.anddev.org/novice-tutorials-f8/get-Frequency-data-from-microphone-in-real-time-t16774.html

希望这会有所帮助。

  1. If you need to update UI thread from any thread you may always use Activity.runOnUiThread(Runnable action). See Activity class javadoc for details.
  2. I'm not sure what exactly do you mean by 'simpy poll the microphone', but in my opinion AudioRecord is a good way to go, when recording micrphone. Here is a link to example implementation, which reads frequency of recorded audio live: http://www.anddev.org/novice-tutorials-f8/get-frequency-data-from-microphone-in-real-time-t16774.html

Hope this helps.

澜川若宁 2024-12-06 22:08:12

It is a late answer but, maybe someone needs an answer for the same question. Here is Open Source Android Oscilloscope (OsciPrime) link (http://android.serverbox.ch/?p=268). The source code uses the Thread instead of AsyncTask. If you see the source code, you can figure out how Thread handles the AudioRecord with Looper and Handler. I hope it is useful to others :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文