Android

Android AudioRecode PCM to wav

Machine_웅 2024. 2. 19. 17:38
728x90
반응형
package com.gitsn.gs_phone.Media;


import android.annotation.SuppressLint;
import android.os.Environment;
import android.util.Log;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.LinkedBlockingQueue;

public class File_Thread extends Thread{
    
    boolean isRun = false;
    LinkedBlockingQueue<byte[]> dataQueue = new LinkedBlockingQueue<>();
    File outputFile = null;
    private static String _SDPath = "";
    String _path2 = "/RecodeDir";

    //---------------------------------------------------------------------

    private BufferedOutputStream mBOStream;
    private final int WAVE_CHANNEL_MONO = 1;  //wav 파일 헤더 생성시 채널 상수값
    private final int HEADER_SIZE = 0x2c; // 44
    private final int RECORDER_BPP = 16;
    private final int RECORDER_SAMPLERATE = 0xac44; // 44100
    private int mAudioLen = 0;


    @SuppressLint("MissingPermission")

    public void startFileSave() {

        if(isRun){
            return;
        }
        isRun = true;
        try {

            isExist();
            _SDPath  = Environment.getExternalStorageDirectory().getAbsolutePath();
            String _path3 = getTime()+".wav";

            outputFile = new File(_SDPath+_path2+"/"+_path3);
            mBOStream = new BufferedOutputStream(new FileOutputStream(outputFile));
            super.start();
        } catch (FileNotFoundException e) {
            Log.d("WLOG_FILE", "File saved to: FileNotFoundException");
        }

        Log.d("WLOG_FILE", "File saved to: start");
    }

    /*
    * 기존 wav 파일에 헤더 부분에 데이터 길이 수정
    * */
    void updateWavHeader(File wav) throws IOException {
        byte[] sizes = ByteBuffer
                .allocate(8)
                .order(ByteOrder.LITTLE_ENDIAN)
                .putInt((int) (wav.length() - 8)) // ChunkSize
                .putInt((int) (wav.length() - 44)) // Chunk Size
                .array();
        RandomAccessFile accessWave = null;
        try {
            accessWave = new RandomAccessFile(wav, "rw"); // 읽기-쓰기 모드로 인스턴스 생성
            // ChunkSize
            accessWave.seek(4); // 4바이트 지점으로 가서
            accessWave.write(sizes, 0, 4); // 사이즈 채움
            // Chunk Size
            accessWave.seek(40); // 40바이트 지점으로 가서
            accessWave.write(sizes, 4, 4); // 채움
        } catch (IOException ex) {
            // 예외를 다시 던지나, finally 에서 닫을 수 있음
            throw ex;
        } finally {
            if (accessWave != null) {
                try {
                    accessWave.close();
                    Log.d("WLOG_FILE", "File saved to: " + outputFile.getAbsolutePath());
                } catch (IOException ex) {
                    // 무시
                    Log.d("WLOG_FILE", "File saved to: IOException ");
                }
            }
        }
    }

    public void stopFileSave(){
        if(!isRun){
            return;
        }
        isRun = false;
        super.interrupt();
    }

    public void pushData(byte [] data){
        try {
            dataQueue.put(data);
        } catch (InterruptedException e) {

        }
    }

    @Override
    public void run() {
        super.run();
        try {
            android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
            mBOStream.write(getFileHeader());
            while (isRun) {
                byte[] datas = dataQueue.take();
                mBOStream.write(datas);
            }
        }
        catch (IOException e) {
            Log.e("WLOG_FILE", "IOException");
        }
        catch (InterruptedException e) {
            Log.e("WLOG_FILE", "InterruptedException");
            try {
                mBOStream.flush();
                mBOStream.close();
                updateWavHeader(outputFile);
                Log.e("WLOG_FILE", "저장완료 ");
            } catch (IOException ex) {
                Log.e("WLOG_FILE", "mBOStream.flush- IOException");
            }
        }

    }

    
    /**
    * .wav 파일 헤더 만들기
    * */
    private byte[] getFileHeader() {
        byte[] header = new byte[HEADER_SIZE];
        int totalDataLen = mAudioLen + 40;
        long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * WAVE_CHANNEL_MONO/8;
        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] = (byte)1;  // format = 1 (PCM방식)
        header[21] = 0;
        header[22] =  WAVE_CHANNEL_MONO;
        header[23] = 0;
        header[24] = (byte) (RECORDER_SAMPLERATE & 0xff);
        header[25] = (byte) ((RECORDER_SAMPLERATE >> 8) & 0xff);
        header[26] = (byte) ((RECORDER_SAMPLERATE >> 16) & 0xff);
        header[27] = (byte) ((RECORDER_SAMPLERATE >> 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) RECORDER_BPP * WAVE_CHANNEL_MONO/8;  // block align
        header[33] = 0;
        header[34] = RECORDER_BPP;  // bits per sample
        header[35] = 0;
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte)(mAudioLen & 0xff);
        header[41] = (byte)((mAudioLen >> 8) & 0xff);
        header[42] = (byte)((mAudioLen >> 16) & 0xff);
        header[43] = (byte)((mAudioLen >> 24) & 0xff);
        return header;
    }

    private  boolean isExist() {
        //' give user permission
        //' <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            _SDPath = Environment.MEDIA_MOUNTED;
            return false;
        }

        _SDPath = Environment.getExternalStorageDirectory().getAbsolutePath();

        //'GSLog.d(_SDPath);

        File file = new File(_SDPath + _path2);
        //' check path
        if (!file.exists()) {
            file.mkdirs();
        }
        return true;
    }

    private String getTime(){
        Date currentTime = new Date();
        // 원하는 형식의 날짜 포맷 지정
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
        // 포맷에 맞게 날짜를 문자열로 변환
        String formattedTime = dateFormat.format(currentTime);
        return formattedTime;
    }

}

 

https://blog.naver.com/PostView.naver?blogId=wonminst&logNo=90130101793

 

[android] 음성 녹음 후 wav 파일 만들기

안드로이드 디바이스에서 AudioRecorder  API를 이용하면 쉽게 음성 녹음을 할 수 있다.  ...

blog.naver.com

 

https://velog.io/@windsekirun/Android-AudioRecord-to-WAV-%EC%98%A4%EB%94%94%EC%98%A4-%EB%85%B9%EC%9D%8C

 

Android - AudioRecord to WAV (오디오 녹음)

이 글은 기존 운영했던 WordPress 블로그인 PyxisPub: Development Life (pyxispub.uzuki.live) 에서 가져온 글 입니다. 모든 글을 가져오지는 않으며, 작성 시점과 현재 시점에는 차이가 많이 존재합니다.작성 시

velog.io

 

728x90
반응형