讯飞语音合成Wav,以及MediaPlayer的一些坑,SeekBar相关知识点

项目中遇到讯飞语音转成WAV,我是这样做的,首先生成.pcm文件,然后再.pcm与.wav互换,最终由MediaPlayer播放,还有进度条之类的小知识点
首先上布局

<?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"
    >
    <EditText
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:id="@+id/edit"/>
<LinearLayout
    android:layout_marginBottom="15dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <Button android:id="@+id/play"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:text="播放"
        />
    <Button android:id="@+id/pause"
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="暂停"
        />

</LinearLayout>


    <SeekBar android:id="@+id/sb"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:max="100"
        />

</LinearLayout>

然后是.pcm与.WAV互换工具类

public class PcmToWavUtil {
    private int mBufferSize;  //缓存的音频大小
    private int mSampleRate = 8000;// 8000|16000
    private int mChannel = AudioFormat.CHANNEL_IN_STEREO;   //立体声
    private int mEncoding = AudioFormat.ENCODING_PCM_16BIT;

    public PcmToWavUtil() {
        this.mBufferSize = AudioRecord.getMinBufferSize(mSampleRate, mChannel, mEncoding);
    }

    /**
     * @param sampleRate sample rate、采样率
     * @param channel    channel、声道
     * @param encoding   Audio data format、音频格式
     */
    public PcmToWavUtil(int sampleRate, int channel, int encoding) {
        this.mSampleRate = sampleRate;
        this.mChannel = channel;
        this.mEncoding = encoding;
        this.mBufferSize = AudioRecord.getMinBufferSize(mSampleRate, mChannel, mEncoding);
    }

    /**
     * pcm文件转wav文件
     *
     * @param inFilename  源文件路径
     * @param outFilename 目标文件路径
     */
    public void pcmToWav(String inFilename, String outFilename) {
        FileInputStream in;
        FileOutputStream out;
        long totalAudioLen;
        long totalDataLen;
        long longSampleRate = mSampleRate;
        int channels = 2;
        long byteRate = 16 * mSampleRate * channels / 8;
        byte[] data = new byte[mBufferSize];
        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 (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 加入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';  //WAVE
        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'; //data
        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);
    }
}

最后看大布局

public class Voice_Activity extends Activity {
    /** Called when the activity is first created. */
    private Voice_BroadcaseUtil voice_broadcaseUtil;
    private EditText edit;
    private Context context=this;
    private  ListView list;
    private  Button play,pause,resume;
    private MediaPlayer mp;
    private   SeekBar sb;
    private Handler handler=new Handler();
    private  int Duration;
    private String content;
   private PcmToWavUtil pcmToWavUtil = new PcmToWavUtil();
    public Voice_Activity voice;
    private List<Voice_Data> voiceData = new ArrayList<>();
    public static String SDPATH ="/sdcard/" ;//获取文件夹
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_voice_test);
        voice=new Voice_Activity();
        initView();
        initData();
        voice_broadcaseUtil=new Voice_BroadcaseUtil(context);
           }


    private void initView() {
        edit=(EditText)findViewById(R.id.edit);
        play=(Button)findViewById(R.id.play);
        pause=(Button)findViewById(R.id.pause);
        sb=(SeekBar)findViewById(R.id.sb);
         mp = new MediaPlayer();
        //找到相应View

        //后面的参数必须是URI形式的,所以要把相应路径转换成URI
        play.setOnClickListener(playlis);
        pause.setOnClickListener(pauselis);
        sb.setOnSeekBarChangeListener(sbLis);
        adapter=new GridAdapter(context,ar);
        list.setAdapter(adapter);
        testRandom1();
    }






    public static void delFile(String fileName){
        File file = new File(SDPATH + fileName);
        if(file.isFile()){
            file.delete();
        }
        file.exists();
    }

    private OnClickListener playlis=new OnClickListener(){
        @Override
        public void onClick(View v) {
            System.out.println(edit.getText().toString().length());
           delFile("speak_result.pcm");//这两行一定要否则,一直都会读上一个文件的内容,导致刷新不及时,点的不是读的
            delFile("speak_result.wav");
            voice_broadcaseUtil.toVoiceStartSave(edit.getText().toString());
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    final String path = "/sdcard/speak_result.pcm" ;
                    final String outpath = path.replace(".pcm", ".wav");
                    pcmToWavUtil.pcmToWav(path, outpath);//转换
                    Toast.makeText(context, "正在拉取资源。请稍后...", Toast.LENGTH_SHORT).show();
                }
            },edit.getText().toString().length()*100);


            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    try {
                        mp.reset();//这句很关键,没有这句会报状态异常错误,而且很难排查
                        mp.setDataSource(context, Uri.parse("/sdcard/speak_result.wav"));
                        mp.prepare();//这句也很重要,没有这句无法正常播放
                        System.out.println("执行了啊");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    Duration=mp.getDuration();//时间
                    sb.setMax(Duration);//进度条最大时间
                    handler.post(start);
                    Toast.makeText(context, "请稍后...", Toast.LENGTH_LONG).show();
                }
            },edit.getText().toString().length()*100);
            //调用handler播放
            }
    };
    Runnable start=new Runnable(){

        @Override
        public void run() {
            mp.start();
            handler.post(updatesb);
            //用一个handler更新SeekBar
        }
    };
    Runnable updatesb =new Runnable(){
        @Override
        public void run() {

                    sb.setProgress(mp.getCurrentPosition());
                    // sb.setProgress();
                    handler.postDelayed(updatesb, 100);//每100毫秒修改一次进度条

              }
    };
    private OnClickListener pauselis=new OnClickListener(){

        @Override
        public void onClick(View v) {
            if(mp.isPlaying()){
                mp.pause();//暂停播放
                pause.setText("继续");
            }else{
                mp.start();//继续播放
                pause.setText("暂停");

            }

        }

    };
    private OnSeekBarChangeListener sbLis=new OnSeekBarChangeListener(){

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress,
                                      boolean fromUser) {
            // TODO Auto-generated method stub
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            // TODO Auto-generated method stub
            mp.seekTo(sb.getProgress());
            //SeekBar确定位置后,跳到指定位置
        }

    };
    public void refresh() {
        onCreate(null);
    }
    private void showTip(String string){
        Toast.makeText(context, string, Toast.LENGTH_SHORT).show();
    }


}

快进和快退

 case R.id.next_up:
                System.out.println("快退");
                mp.seekTo(mp.getCurrentPosition() - 5000);
                break;
            case R.id.next_down:
                mp.seekTo(mp.getCurrentPosition() + 5000);

上几张图
这里写图片描述

猜你喜欢

转载自blog.csdn.net/justingwang_1/article/details/77683941