之前介绍了很多音频知识,最终我们还是希望能够在终端应用到我们的算法,本文主要介绍基础的在Android客户端如何处理我们的音频(wav)格式文件,主要介绍文件的读取,写入和播放。后续再介绍如何进行stft等频域特征提取以及模型的infer方法~
本文的wav处理基础类主要参考https://github.com/Jhuster/AudioDemo中的WavFileReader和WavFileWriter类。
读取音频文件中最主要的步骤是获取了byte[]数据后,我们需要转为float[],因为通常我们的特征提取或者AI模型都是基于float进行的。
// 获取fileReader public WavFileReader open_audio(String wav_path){ WavFileReader m_reader= new WavFileReader(); try { m_reader.openFile(wav_path); } catch (IOException e) { e.printStackTrace(); } return m_reader; }
// 获取音频数据 public float[] read_audio(WavFileReader mfileReader){ // 每次获取PER_PCM_LEN长度的数据 byte[] audioBytes = new byte[PER_PCM_LEN * 2]; int nbytes = mfileReader.readData(audioBytes, 0, audioBytes.length); if (nbytes<=0){ return null; } // 将byte[]转为float[] ShortBuffer sbuf = ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); short[] audioShorts = new short[sbuf.capacity()]; sbuf.get(audioShorts); float[]f_input = new float[audioShorts.length]; for (int i = 0; i < audioShorts.length; i++) { f_input[i] = ((float)audioShorts[i])/0x8000; } return f_input; }
对获取后的音频处理进行一系列处理后,我们需要将处理后的float[]写入音频文件,同样我们需要进行一次float[]到byte[]的转换。
主要代码如下:
// 对writer初始化 mFileWriter = new WavFileWriter(); try { mFileWriter.openFile(wav_out_path, 16000, 1, 16); } catch (IOException e) { e.printStackTrace(); }
// 写入音频文件 public void write_audio(float[] f_writedata){ // 将float[]转换为byte[] byte audioData[]; for (int i=0;i<f_writedata.length; i++){ f_writedata[i] *= 32768.0; } audioData = mFileWriter.shortToByte(mFileWriter.floatToShort(f_writedata)); mFileWriter.writeData(audioData, 0, audioData.length); }
最后我们可以在界面上播放音频,这里函数是播放文件路径的wav音频
void audio_play(String path) { class AudioPlayRunnable implements Runnable { String audio_path; AudioPlayRunnable(String s) { audio_path = s; } public void run() { WavFileReader reader; reader = new WavFileReader(); try { reader.openFile(audio_path); } catch (IOException e) { e.printStackTrace(); } byte[] buffer = new byte[SAMPLES_PER_FRAME * 2]; while (reader.readData(buffer, 0, buffer.length) > 0) { mAudioPlayer.play(buffer, 0, buffer.length); } mAudioPlayer.stopPlayer(); try { reader.closeFile(); } catch (IOException e) { e.printStackTrace(); } } } mAudioPlayer.startPlayer(); Thread t = new Thread(new AudioPlayRunnable(path)); t.start(); }
作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,...
点击 进入React源码调试仓库。 在React的concurrent模式下,低优先级任务执行过...
TOP云 (west.cn)10月16日消息,上周外媒报道了一起争议 域名 仲裁案,一家名为...
域名 必须要实名才能用吗?也不是,目前,在我国 注册域名 ,有少部分域名还不能...
自从双十一成了全民购物狂欢节之后,双十二也理所当然的被当做了降价促销的日子...
1. 接口描述 接口请求域名: cvm.tencentcloudapi.com 。 本接口 (ImportKeyPair...
TOP云 (west.cn)5月24日,此前一枚三数字 域名 520.ren在5月20日当天通过TOP云...
编辑:Sarah 从早期开发的 Elasticsearch 到之后 ELK Stack 的发布,Elastic 在...
近日,专门提供Python服务的网站Troy Labs盘点出了2020年发布的Python库Top10。...
近日,在数据库OceanBase3.0峰会上,蚂蚁集团自主研发的分布式数据库OceanBase首...