首页 新闻 会员 周边 捐助

AudioRecord录音转WAV,播放失真

0
悬赏园豆:20 [已关闭问题] 关闭于 2012-08-24 15:02

用AudioRecord录制的声音是PCM编码,怎么把文件封装成WAV编码的可播放文件呢???

  1 package com.example.recorder;
  2 
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.FileNotFoundException;
  6 import java.io.FileOutputStream;
  7 import java.io.IOException;
  8 
  9 import android.app.Activity;
 10 import android.media.AudioFormat;
 11 import android.media.AudioRecord;
 12 import android.media.MediaRecorder;
 13 import android.os.Bundle;
 14 import android.view.View;
 15 import android.view.View.OnClickListener;
 16 import android.widget.Button;
 17 
 18 public class AudioRecorder extends Activity {
 19     private int audioSource = MediaRecorder.AudioSource.MIC;
 20     // 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
 21 
 22     private static int sampleRateInHz = 44100;
 23     // 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
 24 
 25     private static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;
 26     // 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
 27 
 28     private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
 29     private int bufferSizeInBytes = 0;
 30 
 31     private Button btnRecord;
 32 
 33     // private Button Stop;
 34 
 35     private AudioRecord audioRecord;
 36 
 37     private boolean isRecord = false;// 设置正在录制的状态
 38     // AudioName裸音频数据文件
 39 
 40     private static final String AudioName = "/sdcard/love.raw";
 41     // NewAudioName可播放的音频文件
 42 
 43     private static final String NewAudioName = "/sdcard/new.wav";
 44 
 45     @Override
 46     protected void onCreate(Bundle savedInstanceState) {
 47         // TODO Auto-generated method stub
 48         super.onCreate(savedInstanceState);
 49         setContentView(R.layout.record);
 50         initUI();
 51         initData();
 52         btnRecord.setOnClickListener(new OnClickListener() {
 53 
 54             @Override
 55             public void onClick(View v) {
 56                 // TODO Auto-generated method stub
 57                 if (isRecord) {
 58                     btnRecord.setText("开始录音");
 59                     stop();
 60                 } else {
 61                     btnRecord.setText("正在录音...");
 62                     startRecord();
 63                 }
 64             }
 65         });
 66     }
 67 
 68     public void initUI() {
 69         btnRecord = (Button) findViewById(R.id.btnRecord);
 70     }
 71 
 72     public void initData() {
 73         creatAudioRecord();
 74     }
 75 
 76     private void creatAudioRecord() {
 77 
 78         // 获得缓冲区字节大小
 79 
 80         bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,
 81 
 82         channelConfig, audioFormat);
 83 
 84         // 创建AudioRecord对象
 85 
 86         audioRecord = new AudioRecord(audioSource, sampleRateInHz,
 87 
 88         channelConfig, audioFormat, bufferSizeInBytes);
 89 
 90     }
 91 
 92     private void startRecord() {
 93         audioRecord.startRecording();
 94         // 让录制状态为true
 95         isRecord = true;
 96         // 开启音频文件写入线程
 97         new Thread(new AudioRecordThread()).start();
 98     }
 99 
100     private void stop() {
101         if (audioRecord != null) {
102 
103             System.out.println("stopRecord");
104 
105             isRecord = false;// 停止文件写入
106 
107             audioRecord.stop();
108 
109     
110 
111         }
112     }
113 
114     class AudioRecordThread implements Runnable {
115 
116         @Override
117         public void run() {
118 
119             writeDateTOFile();// 往文件中写入裸数据
120 
121             copyWaveFile(AudioName, NewAudioName);// 给裸数据加上头文件
122 
123         }
124 
125     }
126 
127     /**
128      * 
129      * 这里将数据写入文件,但是并不能播放,因为AudioRecord获得的音频是原始的裸音频,
130      * 
131      * 如果需要播放就必须加入一些格式或者编码的头信息。但是这样的好处就是你可以对音频的 裸数据进行处理,比如你要做一个爱说话的TOM
132      * 
133      * 猫在这里就进行音频的处理,然后重新封装 所以说这样得到的音频比较容易做一些音频的处理。
134      */
135     private void writeDateTOFile() {
136 
137         // new一个byte数组用来存一些字节数据,大小为缓冲区大小
138 
139         byte[] audiodata = new byte[bufferSizeInBytes];
140 
141         FileOutputStream fos = null;
142 
143         int readsize = 0;
144 
145         try {
146 
147             File file = new File(AudioName);
148 
149             if (file.exists()) {
150 
151                 file.delete();
152 
153             }
154 
155             fos = new FileOutputStream(file);// 建立一个可存取字节的文件
156 
157         } catch (Exception e) {
158 
159             e.printStackTrace();
160 
161         }
162 
163         while (isRecord == true) {
164 
165             readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
166 
167             if (AudioRecord.ERROR_INVALID_OPERATION != readsize) {
168 
169                 try {
170                       System.out.println("writeDateTOFile...."+readsize);
171 //                    fos.write(audiodata);
172                     fos.write(audiodata, 0, readsize);
173 
174                 } catch (IOException e) {
175 
176                     e.printStackTrace();
177 
178                 }
179 
180             }
181 
182         }
183 
184         try {
185 
186             fos.close();// 关闭写入流
187 
188         } catch (IOException e) {
189 
190             e.printStackTrace();
191 
192         }
193 
194     }
195 
196     // 这里得到可播放的音频文件
197 
198     private void copyWaveFile(String inFilename, String outFilename) {
199 
200         FileInputStream in = null;
201 
202         FileOutputStream out = null;
203 
204         long totalAudioLen = 0;
205 
206         long totalDataLen = totalAudioLen + 36;
207 
208         long longSampleRate = sampleRateInHz;
209 
210         int channels = 2;
211 
212         long byteRate = 16 * sampleRateInHz * channels / 8;
213 
214         byte[] data = new byte[bufferSizeInBytes];
215 
216         try {
217 
218             in = new FileInputStream(inFilename);
219 
220             out = new FileOutputStream(outFilename);
221 
222             totalAudioLen = in.getChannel().size();
223 
224             totalDataLen = totalAudioLen + 36;
225 
226             WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
227 
228             longSampleRate, channels, byteRate);
229                   int size=0;
230             while ((size = in.read(data)) != -1) {
231              System.out.println("copyWaveFile...."+size);
232                 out.write(data,0,size);
233 
234             }
235 
236             in.close();
237 
238             out.close();
239 
240         } catch (FileNotFoundException e) {
241 
242             e.printStackTrace();
243 
244         } catch (IOException e) {
245 
246             e.printStackTrace();
247 
248         }
249 
250     }
251 
252     /**
253      * 
254      * 这里提供一个头信息。插入这些信息就可以得到可以播放的文件。
255      * 
256      * 
257      * 音频的文件,可以发现前面的头文件可以说基本一样哦。每种格式的文件都有
258      * 
259      * 自己特有的头文件。
260      */
261 
262     private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen,
263 
264     long totalDataLen, long longSampleRate, int channels, long byteRate)
265 
266     throws IOException {
267 
268         byte[] header = new byte[44];
269 
270         header[0] = 'R'; // RIFF/WAVE header
271 
272         header[1] = 'I';
273 
274         header[2] = 'F';
275 
276         header[3] = 'F';
277 
278         header[4] = (byte) (totalDataLen & 0xff);
279 
280         header[5] = (byte) ((totalDataLen >> 8) & 0xff);
281 
282         header[6] = (byte) ((totalDataLen >> 16) & 0xff);
283 
284         header[7] = (byte) ((totalDataLen >> 24) & 0xff);
285 
286         header[8] = 'W';
287 
288         header[9] = 'A';
289 
290         header[10] = 'V';
291 
292         header[11] = 'E';
293 
294         header[12] = 'f'; // 'fmt ' chunk
295 
296         header[13] = 'm';
297 
298         header[14] = 't';
299 
300         header[15] = ' ';
301 
302         header[16] = 16; // 4 bytes: size of 'fmt ' chunk
303 
304         header[17] = 0;
305 
306         header[18] = 0;
307 
308         header[19] = 0;
309 
310         header[20] = 1; // format = 1
311 
312         header[21] = 0;
313 
314         header[22] = (byte) channels;
315 
316         header[23] = 0;
317 
318         header[24] = (byte) (longSampleRate & 0xff);
319 
320         header[25] = (byte) ((longSampleRate >> 8) & 0xff);
321 
322         header[26] = (byte) ((longSampleRate >> 16) & 0xff);
323 
324         header[27] = (byte) ((longSampleRate >> 24) & 0xff);
325 
326         header[28] = (byte) (byteRate & 0xff);
327 
328         header[29] = (byte) ((byteRate >> 8) & 0xff);
329 
330         header[30] = (byte) ((byteRate >> 16) & 0xff);
331 
332         header[31] = (byte) ((byteRate >> 24) & 0xff);
333 
334         header[32] = (byte) (2 * 16 / 8); // block align
335 
336         header[33] = 0;
337 
338         header[34] = 16; // bits per sample
339 
340         header[35] = 0;
341 
342         header[36] = 'd';
343 
344         header[37] = 'a';
345 
346         header[38] = 't';
347 
348         header[39] = 'a';
349 
350         header[40] = (byte) (totalAudioLen & 0xff);
351 
352         header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
353 
354         header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
355 
356         header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
357 
358         out.write(header, 0, 44);
359 
360     }
361 
362     @Override
363     protected void onDestroy() {
364 
365         stop();
366         audioRecord.release();// 释放资源
367 
368         audioRecord = null;
369         super.onDestroy();

这是我在网上的一个转换方式,但保存后文件都严重失真,不知道哪儿不对,谁错过?给点意见。。。

问题补充:

有没有人知道呢

为梦奔跑的主页 为梦奔跑 | 初学一级 | 园豆:60
提问于:2012-08-10 16:37
< >
分享
所有回答(1)
0

请问您的问题解决了吗?我也遇到了一样的问题!

yeshiyuan | 园豆:201 (菜鸟二级) | 2014-10-20 11:30
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册