AndroidでAudioRecordが使用

12379 ワード

この文書は次のとおりです.http://blog.csdn.net/xiaomao5200/article/details/7716216
オーディオのサンプリングレートとサンプリングサイズとは  
自然界の音は非常に複雑で,波形は極めて複雑で,通常パルスコード変調符号化を採用している.すなわちPCM符号化である.PCMは、サンプリング、量子化、符号化の3つのステップにより、連続的に変化するアナログ信号をデジタル符号化に変換する.サンプリング:オーディオ収集ではサンプリングレートと呼ばれます.音は実はエネルギー波であるため、周波数と振幅の特徴もあり、周波数は時間軸線に対応し、振幅はレベル軸線に対応する.波は無限に滑らかで,弦線は無数の点から構成されていると見なすことができ,記憶空間が相対的に限られているため,デジタル符号化の過程で弦線の点をサンプリングしなければならない.サンプリングの過程はある点の周波数値を抽出することであり、明らかに、1秒で抽出できる点が多ければ多いほど、取得周波数情報が豊富になり、波形を復元するためには、1回の振動で2点のサンプリングが必要であり、人耳が感じる最高周波数は20 kHzであるため、人耳の聴覚要求を満たすには、少なくとも毎秒40 k回のサンプリングを行い、40 kHzで表現する必要がある.この40 kHzがサンプリングレートです.我々の一般的なCDは、44.1 kHzのサンプリングレートです.
量子化:ここでのサンプリングサイズは量子化の過程です.
この周波数のエネルギー値を量子化し、信号強度を表す.量子化レベル数2の整数次べき乗,我々の一般的なCDビット16 bitのサンプリングサイズ,すなわち2の16乗.
符号化:サンプリングレートとサンプリングサイズによって、自然界に対する信号、オーディオ符号化は最大で無限に近づくしかなく、少なくとも現在の技術はこのようにするしかなく、自然界に対する信号、いかなるデジタルオーディオ符号化案も損なわれている.完全に復元できないからだ.コンピュータの応用の中で、最高の保真レベルに達することができるのはPCMコードで、広く素材の保存と音楽の鑑賞に用いられて、CD、DVDと私達のよくあるWAVファイルの中ですべて応用があります.従って、PCMは、デジタルオーディオにおける最適な忠実度レベルを表すため、PCMが信号の絶対的な忠実度を確保できるという意味ではなく、PCMも最大限に無限に近づくしかないので、無損符号化として定着している.我々は習慣的にMP 3を有損オーディオ符号化の範疇に入れ、PCM符号化に相対している.符号化の相対性の有損と無損を強調するのは、真の無損を実現することは困難であることを伝えるためであり、円周率を数字で表現するように、精度がどんなに高くても、無限に近いだけで、真の円周率に等しい値ではなく、なぜオーディオ圧縮技術を使用するのかを教えるためである. 
PCMオーディオストリームの符号レートを計算するのは簡単です.サンプリングレート値×サンプルサイズ値×チャネル数bps.サンプリングレート44.1 KHz、サンプリングサイズ16 bit、デュアルチャネルPCM符号化WAVファイル、データレート44.1 K×16×2 =1411.2 Kbps.128 KのMP 3とよく言われていますが、対応するWAVのパラメータは、この1411.2 Kbpsで、このパラメータはデータ帯域幅とも呼ばれ、ADSLの帯域幅と概念です.符号レートを8で割ると、このWAVのデータレート、すなわち176.4 KB/sが得られる.これは、1秒のサンプリングレート44.1 KHz、サンプリングサイズ16 bit、デュアルチャネルのPCM符号化オーディオ信号を格納するには176.4 KBの空間が必要であり、1分で約10.34 Mであることを示しており、ほとんどのユーザーには受け入れられない.特にパソコンで音楽を聴くのが好きな友人は、ディスクの占有量を下げるには、サンプリング指標や圧縮を下げる2つの方法しかない.指標を下げるのは望ましくないため、専門家たちは様々な圧縮案を開発した.用途とターゲット市場が異なるため,様々なオーディオ圧縮符号化が達成する音質と圧縮比が異なり,後述する.一つは間違いなく、彼らは圧縮したことがある. 
周波数とサンプリングレートの関係 
サンプリングレートは1秒あたりの元の信号のサンプリング回数を表し、私たちがよく見られるオーディオファイルのサンプリングレートは44.1 KHzが多いが、これは何を意味しているのだろうか.もし私たちが2段の正弦波信号を持っていて、それぞれ20 Hzと20 KHzで、長さはすべて1秒で、私たちが聞くことができる最低周波数と最高周波数に対応して、それぞれこの2段の信号に対して40 KHzのサンプリングを行って、私たちはどんな結果を得ることができますか?その結果,20 Hzの信号は振動毎に40 K/20=2000回サンプリングされたが,20 Kの信号は振動毎に2回しかサンプリングされなかった.同じサンプリングレートでは,記録低周波数の情報は高周波数の詳細よりはるかに大きいことが明らかになった.これもなぜ一部の音響熱狂者がCDにデジタル音が真実ではないと非難しているのか、CDの44.1 KHzサンプリングも高周波信号が記録されることを保証できない.高周波信号をよりよく記録するには、より高いサンプリングレートが必要になるようです.そこで、CDトラックを捕まえるときに48 KHzのサンプリングレートを使う友达もいます.これは望ましくありません.これは実際には音質に何のメリットもありません.レールソフトウェアにとって、CDが提供する44.1 KHzと同じサンプリング率を維持することが、それを向上させるのではなく、最適な音質の保証の一つです.より高いサンプリングレートは、アナログ信号に対してのみ使用できます.サンプリングされた信号が数値である場合は、サンプリングレートの向上を試みないでください. 
ストリームフィーチャー 
インターネットの発展に伴い、人々はオンラインで音楽を聴くことを要求しているため、オーディオファイルを読みながら再生することができ、このファイルを全部読んでから再生する必要がなく、ダウンロードせずに聴くことができるようになった.コードしながら再生できるのが特徴で、オンラインでの生放送が可能になり、独自のデジタル放送局を架けることが現実になった.    
 
二androidにおけるAudioRecord採集オーディオのパラメータ説明
androidでオーディオを収集するapiはandroid.media.AudioRecordクラス
コンストラクタのいくつかのパラメータが標準的な音声収集パラメータです
以下はパラメータの意味解釈です
public AudioRecord (int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)
Since: API Level 3
Class constructor.
Parameters
audioSource
the recording source. See MediaRecorder.AudioSource for recording source definitions.オーディオソース:どこからオーディオを収集するかを指します.ここではもちろんマイクからオーディオを採取するので、このパラメータの値はMICです.
sampleRateInHz
the sample rate expressed in Hertz.Examples of rates are(but not limited to)44100,22050 and 11025.サンプリング率:オーディオのサンプリング周波数、毎秒サンプリングできる回数、サンプリング率が高いほど音質が高くなる.与えられた例は44100、22050、11025であるが、これらのパラメータに限定されない.例えば、低品質のオーディオを収集するには、4000、8000などの低サンプリングレートを使用することができる.
channelConfig
describes the configuration of the audio channels. SeeCHANNEL_IN_MONO and CHANNEL_IN_STREOチャネル設定:androidはデュアルチャネルステレオとシングルチャネルをサポートします.MONOモノラル、STREOステレオ
audioFormat
the format in which the audio data is represented. SeeENCODING_PCM_16BIT and ENCODING_PCM_8 BIT符号化方式とサンプリングサイズ:採取したデータは当然PCM符号化(パルスコード変調符号化、すなわちPCM符号化)を使用する.PCMはサンプリング、量子化、符号化の3段階により連続的に変化するアナログ信号をデジタル符号化に変換する.)androidがサポートするサンプリングサイズ16 bitまたは8 bit.もちろんサンプリングサイズが大きいほど、情報量が多くなり、音質も高くなり、現在主流のサンプリングサイズは16 bitであり、低品質の音声伝送時には8 bitである 十分です.
bufferSizeInBytes
the total size (in bytes) of the buffer where audio data is written to during the recording. New audio data can be read from this buffer in smaller chunks than this size. See getMinBufferSize(int,int,int)to determine the minimum required buffer size for the successful creation of an AudioRecord instance.Using values smaller than getMinBufferSize()will result in an initialization failure.データ収集に必要なバッファのサイズは、最小必要なサイズが分からない場合はgetMinBufferSize()で表示できます.
収集されたデータはbyteBufferに保存され、ストリームを使用して読み出すことができます.ファイルとして保存することもできます
 
三A ndroid AudioRecordを使用した録音関連およびオーディオファイルのパッケージ
Androidで録音するにはMediaRecordで録音でき、操作が簡単です.しかし、専門性が足りないのは、オーディオの処理ができないことです.オーディオのリアルタイムの処理やオーディオのパッケージを行う場合
AudioRecordで録音できます.
ここではコードを示します.AudioRecordの録音とWAV形式オーディオのパッケージ化を実現した.
AudioTrackとAudioTrackクラスでは、録画しながら放送することができます.参考にしてください.http://blog.sina.com.cn/s/blog_6309e1ed0100j1rw.html
ここのコードは再生されていません.しかし、パッケージと詳細は以下の通りです.
package com.ppmeet;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.graphics.PixelFormat;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;

/**
 * class name:TestAudioRecord<BR>
 * class description: AudioRecord     <BR>
 * PS: <BR>
 * 
 * @version 1.00 2011/09/21
 * @author CODYY)peijiangping
 */
public class TestAudioRecord extends Activity {
	//      
	private int audioSource = MediaRecorder.AudioSource.MIC;
	//        ,44100      ,          22050,16000,11025
	private static int sampleRateInHz = 44100;
	//           CHANNEL_IN_STEREO    ,CHANNEL_CONFIGURATION_MONO    
	private static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;
	//       :PCM 16     。      。PCM 8     。          。
	private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
	//        
	private int bufferSizeInBytes = 0;
	private Button Start;
	private Button Stop;
	private AudioRecord audioRecord;
	private boolean isRecord = false;//          
	//AudioName       
	private static final String AudioName = "/sdcard/love.raw";
	//NewAudioName        
	private static final String NewAudioName = "/sdcard/new.wav";

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		getWindow().setFormat(PixelFormat.TRANSLUCENT);//      
		requestWindowFeature(Window.FEATURE_NO_TITLE);//       
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		//         
		setContentView(R.layout.main);
		init();
	}

	private void init() {
		Start = (Button) this.findViewById(R.id.start);
		Stop = (Button) this.findViewById(R.id.stop);
		Start.setOnClickListener(new TestAudioListener());
		Stop.setOnClickListener(new TestAudioListener());
		creatAudioRecord();
	}

	private void creatAudioRecord() {
		//          
		bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,
				channelConfig, audioFormat);
		//   AudioRecord  
		audioRecord = new AudioRecord(audioSource, sampleRateInHz,
				channelConfig, audioFormat, bufferSizeInBytes);
	}

	class TestAudioListener implements OnClickListener {

		@Override
		public void onClick(View v) {
			if (v == Start) {
				startRecord();
			}
			if (v == Stop) {
				stopRecord();
			}

		}

	}

	private void startRecord() {
		audioRecord.startRecording();
		//       true
		isRecord = true;
		//           
		new Thread(new AudioRecordThread()).start();
	}

	private void stopRecord() {
		close();
	}

	private void close() {
		if (audioRecord != null) {
			System.out.println("stopRecord");
			isRecord = false;//      
			audioRecord.stop();
			audioRecord.release();//    
			audioRecord = null;
		}
	}

	class AudioRecordThread implements Runnable {
		@Override
		public void run() {
			writeDateTOFile();//         
			copyWaveFile(AudioName, NewAudioName);//         
		}
	}

	/**
	 *          ,       ,  AudioRecord            ,
	 *                        。                        ,           TOM
	 *             ,                             。
	 */
	private void writeDateTOFile() {
		// new  byte           ,        
		byte[] audiodata = new byte[bufferSizeInBytes];
		FileOutputStream fos = null;
		int readsize = 0;
		try {
			File file = new File(AudioName);
			if (file.exists()) {
				file.delete();
			}
			fos = new FileOutputStream(file);//             
		} catch (Exception e) {
			e.printStackTrace();
		}
		while (isRecord == true) {
			readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
			if (AudioRecord.ERROR_INVALID_OPERATION != readsize) {
				try {
					fos.write(audiodata);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		try {
			fos.close();//      
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	//             
	private void copyWaveFile(String inFilename, String outFilename) {
		FileInputStream in = null;
		FileOutputStream out = null;
		long totalAudioLen = 0;
		long totalDataLen = totalAudioLen + 36;
		long longSampleRate = sampleRateInHz;
		int channels = 2;
		long byteRate = 16 * sampleRateInHz * channels / 8;
		byte[] data = new byte[bufferSizeInBytes];
		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();
		}
	}

	/**
	 *          。                  。
	 *        44   ,         ,         wav
	 *      ,                  。         
	 *         。
	 */
	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'; // RIFF/WAVE header
		header[1] = 'I';
		header[2] = 'F';
		header[3] = 'F';
		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'; // 'fmt ' chunk
		header[13] = 'm';
		header[14] = 't';
		header[15] = ' ';
		header[16] = 16; // 4 bytes: size of 'fmt ' chunk
		header[17] = 0;
		header[18] = 0;
		header[19] = 0;
		header[20] = 1; // format = 1
		header[21] = 0;
		header[22] = (byte) channels;
		header[23] = 0;
		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); // block align
		header[33] = 0;
		header[34] = 16; // bits per sample
		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);
		out.write(header, 0, 44);
	}

	@Override
	protected void onDestroy() {
		close();
		super.onDestroy();
	}
}

PS:最后にプログラムに录音権限とsdカードを书く権限を忘れないでください...