Bass库录音

Bass库录音与播放实战

代码地址:https://download.youkuaiyun.com/download/qq_14931305/10803169

Bass库官网:http://www.un4seen.com/

Bass库参考文档:http://www.un4seen.com/doc/#bass/bass.html

1.Bass库集成

集成请参考我之前的博客:https://blog.youkuaiyun.com/qq_14931305/article/details/84374301

2.录音完整代码

代码地址:https://download.youkuaiyun.com/download/qq_14931305/10810927

3.录音实现

  1. BASSRecord类 
    package com.lin.bassrecorddemo;
    
    import android.util.Log;
    
    import com.un4seen.bass.BASS;
    
    import java.io.File;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    
    /**
     * Created by jiedoushi on 2018/11/27.
     */
    
    public class BASSRecord implements  BASS.RECORDPROC{
        private static final String pathRecordRaw ="/storage/emulated/0/BASSRecord/"+System.currentTimeMillis()+".raw";
        private String pathRecordWav;
        private static final int DEFAULT_SAMPLING_RATE =44100;
        private static final int DEFAULT_WAV_CHANNEL =1;//通道
        private BassDataEncodeThread mEncodeThread;
        private int chan;
    
        @Override
        public boolean RECORDPROC(int handle, ByteBuffer byteBuffer, int length, Object user) {
            //write raw file
            int byteSize = byteBuffer.capacity();
            mEncodeThread.addTask(byteBuffer, byteSize);
            mEncodeThread.writeData();
            byteBuffer.position(0);
            return true;
        }
    
        private void init(){
            File file =new File(pathRecordRaw);
            if(!file.getParentFile().exists()){
                file.getParentFile().mkdirs();
            }
            if (!file.exists()){
    
            }
            pathRecordWav =pathRecordRaw.replace(".raw",".wav");
            mEncodeThread = new BassDataEncodeThread(pathRecordRaw);
            mEncodeThread.start();
    
            // setup recording device (using default device)
            if (!BASS.BASS_RecordInit(-1)) {
                Error("Can't initialize recording device");
            }
        }
    
        public void startRecord(){
            init();
            // start recording
            Log.e("BASSRecorder","录音信息sampl="+DEFAULT_SAMPLING_RATE+
                    " channels="+DEFAULT_WAV_CHANNEL);
            if (BASS.BASS_RecordStart(DEFAULT_SAMPLING_RATE, DEFAULT_WAV_CHANNEL, 0, this, 0) == 0) {
                Error("Couldn't start recording");
            }
        }
    
        public void stopRecord(){
            try {
                BASS.BASS_RecordFree();
                mEncodeThread.stopWrite();
                File wavFile =new File(pathRecordWav);
                if (wavFile.exists()){
                    wavFile.createNewFile();
                }
                File fileRaw= new File(pathRecordRaw);
                WavPcmUtil.saveRawAsWavFile(fileRaw, 1, wavFile, null);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public void playMusic(){
            if (!BASS.BASS_Init(-1,44100,0)) {
                Error("Can't initialize device");
                return;
            }else {
                chan=BASS.BASS_StreamCreateFile(pathRecordWav,0L,0L,BASS.BASS_SAMPLE_FLOAT);
                if (chan == 0){
                    Error("Can't initialize BASS_StreamCreateFile");
                    return;
                }
                if (!BASS.BASS_ChannelPlay(chan, true)) // play the recorded data
                    Error("Cannot Play");
            }
    
        }
        public void stopMusic(){
            BASS.BASS_ChannelStop(chan);
            BASS.BASS_StreamFree(chan);
            BASS.BASS_Stop();
            BASS.BASS_Free();
        }
    
    
        // display error messages
        void Error(String es) {
            Log.e("BASSRecorder","PROCESS_ERROR ");
    
            BASS.BASS_RecordFree();
            // get error code in current thread for display in UI thread
            String s=String.format("%s\n(error code: %d)", es, BASS.BASS_ErrorGetCode());
            Log.e("BASSRecorder","BASS_ErrorGetCode= "+s);
        }
    }
    
  2. BassDataEncodeThread类
    package com.lin.bassrecorddemo;
    
    import android.os.HandlerThread;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    /**
     * Created by jiedoushi on 2018/11/27.
     */
    
    public class BassDataEncodeThread extends HandlerThread {
        private String pathRecord;
        private FileChannel mFileChannel;
    
        public BassDataEncodeThread(String path) {
            super("BassDataEncodeThread");
            pathRecord =path;
            File file =new File(path);
            try {
                this.mFileChannel = new FileOutputStream(file).getChannel();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        public void writeData(){
            if (mTasks.size() > 0) {
                Task task = mTasks.remove(0);
                ByteBuffer byteBuffer = task.getData();
                int readSize = task.getReadSize();
                if (readSize > 0) {
                    try {
                        mFileChannel.write(byteBuffer);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        public void stopWrite(){
            try {
                mFileChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            getLooper().quit();
        }
    
        private List<Task> mTasks = Collections.synchronizedList(new ArrayList<Task>());
    
        void addTask(ByteBuffer rawData, int readSize) {
            mTasks.add(new Task(rawData, readSize));
        }
    
        private class Task {
            private ByteBuffer rawData;
            private int readSize;
    
            Task(ByteBuffer rawData, int readSize) {
                this.rawData = rawData;
                this.readSize = readSize;
            }
    
            public ByteBuffer getData() {
                return rawData;
            }
    
            int getReadSize() {
                return readSize;
            }
        }
    
    }
    

     

  3. MainActivity类
    package com.lin.bassrecorddemo;
    
    import android.Manifest;
    import android.content.pm.PackageManager;
    import android.os.Build;
    import android.support.v4.app.ActivityCompat;
    import android.support.v4.content.ContextCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    
    public class MainActivity extends AppCompatActivity {
        private BASSRecord record;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            requestVibratePermission();
    
            findViewById(R.id.btnStart).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (record == null) {
                        record = new BASSRecord();
                    }
    
                    record.startRecord();
                }
            });
    
            findViewById(R.id.btnStop).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    record.stopRecord();
                }
            });
    
            findViewById(R.id.btnPlay).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    record.playMusic();
                }
            });
    
            findViewById(R.id.btnStopMusic).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    record.stopMusic();
                }
            });
        }
    
        /**
         * 申请振动权限
         */
        public boolean requestVibratePermission (){
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
                        || ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
                        ||ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(MainActivity.this,
                            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
                                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
                                    Manifest.permission.RECORD_AUDIO},
                            1001);
                    Log.e("phonevibrate", "权限未申请");
                    return false;
                } else {
                    Log.e("phonevibrate", "权限已经申请");
                    return true;
                }
            }
            return true;
        }
    }
    
  4. AndroidManifest.xml权限添加

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

     

  5. WavPcmUtil类,wav文件头定义
    package com.lin.bassrecorddemo;
    
    import android.util.Log;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;
    import java.util.List;
    
    /**
     * Created by jiedoushi on 2017/11/22.
     *
     public static void testVolume() {
     try {
     File a = new File("/sdcard/PerfectPiano/test/a.wav");
    
     File c = new File("/sdcard/PerfectPiano/test/c.raw");
     File d = new File("/sdcard/PerfectPiano/test/d.wav");
     if (c.exists()) {
     c.delete();
     }
     c.createNewFile();
    
     if(d.exists()) {
     d.delete();
     }
     d.createNewFile();
    
     setWavFileVolume(a, 0.1, c,null);
     saveRawAsWavFile(c, 1, d, null);
     } catch (IOException e) {
     e.printStackTrace();
     }
     }
    
     public static void test() {
     try {
     File a = new File("/sdcard/PerfectPiano/test/a.raw");
     File b = new File("/sdcard/PerfectPiano/test/b.wav");
     File c = new File("/sdcard/PerfectPiano/test/c.raw");
     File d = new File("/sdcard/PerfectPiano/test/d.wav");
     if (c.exists()) {
     c.delete();
     }
     c.createNewFile();
    
     if(d.exists()) {
     d.delete();
     }
     d.createNewFile();
     mergeWavToRawFile(a, b, c);
     saveRawAsWavFile(c, 1, d);
     }catch (IOException e) {
     e.printStackTrace();
     }
    
     }
    
     public static void test2() {
     try {
    
     File a = new File("/sdcard/PerfectPiano/test/b.wav");
     File b = new File("/sdcard/PerfectPiano/test/d.wav");
     File c = new File("/sdcard/PerfectPiano/test/c.raw");
     File d = new File("/sdcard/PerfectPiano/test/e.wav");
    
     List<File> inputList = new ArrayList<>();
     inputList.add(a);
     inputList.add(b);
    
     List<Integer> timelist = new ArrayList<>();
     timelist.add(3000);
     timelist.add(120000);
    
     if (c.exists()) {
     c.delete();
     }
     c.createNewFile();
    
     if(d.exists()) {
     d.delete();
     }
     d.createNewFile();
    
     spliceWavFiles(inputList, timelist, c);
     saveRawAsWavFile(c, 1, d);
    
     }catch (IOException e) {
     e.printStackTrace();
     }
    
     }
    
    
     public static void test3() {
     try {
    
     File a = new File("/sdcard/PerfectPiano/test/b.wav");
     File b = new File("/sdcard/PerfectPiano/test/f.raw");
     File c = new File("/sdcard/PerfectPiano/test/g.raw");
     File d = new File("/sdcard/PerfectPiano/test/h.wav");
     File e = new File("/sdcard/PerfectPiano/test/i.wav");
    
    
     if (b.exists()) {
     b.delete();
     }
     b.createNewFile();
     if (c.exists()) {
     c.delete();
     }
     c.createNewFile();
    
     if(d.exists()) {
     d.delete();
     }
     d.createNewFile();
    
     if(e.exists()) {
     e.delete();
     }
     e.createNewFile();
    
     int channelCount = splitWavFile(a, 30000, b, c);
     saveRawAsWavFile(b, channelCount, d);
     saveRawAsWavFile(c, channelCount, e);
     }catch (IOException e) {
     e.printStackTrace();
     }
    
     }
     */
    
    
    public class WavPcmUtil {
    
        public static final int DEFAULT_SAMPLING_RATE = 44100;
    
        public interface WavOperationCallback {
            void wavOperationComplete();
            void wavOperationError();
        }
    
        /**
         * 将PCM RAW DATA存储为.wav文件
         * @param rawInputFile
         * @param channels
         * @param outputWavFile
         * @throws IOException
         */
        public static void saveRawAsWavFile(File rawInputFile, int channels, File outputWavFile, WavOperationCallback callback) throws IOException {
            if(rawInputFile == null || outputWavFile == null) {
                throw new IOException();
            }
            FileInputStream fis = new FileInputStream(rawInputFile);
            FileOutputStream fos = new FileOutputStream(outputWavFile);
            Log.e("WavPcmUtil", "save start");
            int fileLength = (int)rawInputFile.length();
            createWavHeader(fos, fileLength, (short) channels, DEFAULT_SAMPLING_RATE, (short) 16);
    
            byte[] data = new byte[512];
            int length = 0;
            while ((length = fis.read(data)) != -1) {
                fos.write(data, 0, length);
            }
            Log.e("WavPcmUtil", "save end");
            fos.flush();
            fos.close();
            fis.close();
            if (callback!=null) {
                callback.wavOperationComplete();
            }
        }
        /**
         * 创建.wav文件头,并写入output stream.
         * @param fos: 写入的文件
         * @param rawLength: raw文件数据长度
         * @param channel: 声道数量
         * @param sampleRate: 采样率
         * @param bitPerSample: 比特率
         * @throws IOException
         */
        public static void createWavHeader(FileOutputStream fos, int rawLength, short channel,
                                           int sampleRate, short bitPerSample) throws IOException {
            byte[] data = new byte[1];
    
            // RIFF
            data[0] = 'R';
            fos.write(data);
            data[0] = 'I';
            fos.write(data);
            data[0] = 'F';
            fos.write(data);
            data[0] = 'F';
            fos.write(data);
    
            int fileLength = rawLength + (44 - 8);
            fos.write(intToByteArray(fileLength));
    
            // WAVE
            data[0] = 'W';
            fos.write(data);
            data[0] = 'A';
            fos.write(data);
            data[0] = 'V';
            fos.write(data);
            data[0] = 'E';
            fos.write(data);
    
            // fmt
            data[0] = 'f';
            fos.write(data);
            data[0] = 'm';
            fos.write(data);
            data[0] = 't';
            fos.write(data);
            data[0] = ' ';
            fos.write(data);
    
            int size = 16;
            fos.write(intToByteArray(size));
    
            short fmtTag = 1;
            fos.write(shortToByteArray(fmtTag));
    
            fos.write(shortToByteArray(channel));
            fos.write(intToByteArray(sampleRate));
    
            short blockAlign = (short)(channel * bitPerSample / 8);
            int bytePerSec = blockAlign * sampleRate;
            fos.write(intToByteArray(bytePerSec));
            fos.write(shortToByteArray(blockAlign));
            fos.write(shortToByteArray(bitPerSample));
    
            // data
            data[0] = 'd';
            fos.write(data);
            data[0] = 'a';
            fos.write(data);
            data[0] = 't';
            fos.write(data);
            data[0] = 'a';
            fos.write(data);
    
            // data size
            fos.write(intToByteArray(rawLength));
        }
        /**
         * 将int转化为byte[]
         */
        private static byte[] intToByteArray(int data) {
            return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(data).array();
        }
    
        /**
         * 将short转化为byte[]
         */
        private static byte[] shortToByteArray(short data) {
            return ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(data).array();
        }
    
    }
    

    代码已经全部上传,希望能帮到你们!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值