//
//  PQCreateEmptyWAV.swift
//  PQSpeed
//
//  Created by ak on 2020/9/16.
//  Copyright © 2020 BytesFlow. All rights reserved.
//  功能： 生成指定长度的空 WAV 文件
/*
    e.g.
    let tool = LYEmptyWAV(sampleRate: 44100,
                                channel: 1,
                                duration: 20,
                                bit: 16);

          var documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! as String
          documentPath.append("/test.wav")
          tool.createEmptyWAVFile(url: URL(fileURLWithPath: documentPath))

     600 s  622028807.468433  622028844.650877
 */

import UIKit

import AudioToolbox
import Foundation
public class PQCreateEmptyWAV {
    // 采样率
    private var mSampleRate: Double = 44100

    // 声道
    private var mChannel: Double = 1
    // 时长
    private var mduration: Double = 5.0
    // 采样位数
    private var mbit: Double = 16
    public init(sampleRate: Double = 44100, channel: Double = 1, duration: Double, bit: Double = 16) {
        mSampleRate = sampleRate
        mChannel = channel
        mduration = duration
        mbit = bit
        if mduration == 0 {
            BFLog(message: "时长为0？？")
        }
        BFLog(message: "mSampleRate is\(mSampleRate) mChannel is \(mChannel) mduration is:\(mduration) mbit is \(mbit)")
    }

    public func createEmptyWAVFile(url: URL, completeHander: @escaping (_ fileURL: URL?) -> Void) {
        DispatchQueue.global().async {
            // 数字音频文件大小（Byte) = 采样频率（Hz）× 采样时长（S）×（采样位数 / 8）× 声道数（单声道为1，立体声为2）
//        BFLog(message: "createEmptyWAVFile 1")
            let size = Int64(self.mSampleRate * self.mduration * (self.mbit / 8) * self.mChannel)

            let bufer = Array(repeating: 0, count: Int(size))
//        BFLog(message: "createEmptyWAVFile 2 \(size)")
            let data = Data(bytes: bufer, count: Int(size))
            let totalAudioLen = size
            let totalDataLen = totalAudioLen + 44
//        BFLog(message: "createEmptyWAVFile 3")
            self.writewaveFileHeader(output: url,
                                     totalAudioLen: totalAudioLen,
                                     totalDataLen: totalDataLen,
                                     longSampleRate: Int64(self.mSampleRate),
                                     channels: Int(self.mChannel),
                                     byteRate: size,
                                     audioData: data)

            DispatchQueue.main.async {
                completeHander(url)
            }
        }
    }

    public func createEmptyWAVFile(url: URL) {
        // 数字音频文件大小（Byte) = 采样频率（Hz）× 采样时长（S）×（采样位数 / 8）× 声道数（单声道为1，立体声为2）
//        BFLog(message: "createEmptyWAVFile 1")
        let size = Int64(mSampleRate * mduration * (mbit / 8) * mChannel)

        let bufer = Array(repeating: 0, count: Int(size))
//        BFLog(message: "createEmptyWAVFile 2 \(size)")
        let data = Data(bytes: bufer, count: Int(size))
        let totalAudioLen = size
        let totalDataLen = totalAudioLen + 44
//        BFLog(message: "createEmptyWAVFile 3")
        writewaveFileHeader(output: url,
                            totalAudioLen: totalAudioLen,
                            totalDataLen: totalDataLen,
                            longSampleRate: Int64(mSampleRate),
                            channels: Int(mChannel),
                            byteRate: size,
                            audioData: data)
    }

    public func writewaveFileHeader(output: URL, totalAudioLen: Int64,
                                    totalDataLen: Int64,
                                    longSampleRate: Int64,
                                    channels: Int,
                                    byteRate: Int64,
                                    audioData: Data)
    {
        BFLog(message: "createEmptyWAVFile 4")
        var header: [UInt8] = Array(repeating: 0, count: 44)

        // RIFF/WAVE header
        header[0] = UInt8(ascii: "R")
        header[1] = UInt8(ascii: "I")
        header[2] = UInt8(ascii: "F")
        header[3] = UInt8(ascii: "F")
        header[4] = (UInt8)(totalDataLen & 0xFF)
        header[5] = (UInt8)((totalDataLen >> 8) & 0xFF)
        header[6] = (UInt8)((totalDataLen >> 16) & 0xFF)
        header[7] = (UInt8)((totalDataLen >> 24) & 0xFF)

        // WAVE
        header[8] = UInt8(ascii: "W")
        header[9] = UInt8(ascii: "A")
        header[10] = UInt8(ascii: "V")
        header[11] = UInt8(ascii: "E")

        // 'fmt' chunk
        header[12] = UInt8(ascii: "f")
        header[13] = UInt8(ascii: "m")
        header[14] = UInt8(ascii: "t")
        header[15] = UInt8(ascii: " ")

        // 4 bytes: size of 'fmt ' chunk
        header[16] = 16
        header[17] = 0
        header[18] = 0
        header[19] = 0

        // format = 1
        header[20] = 1
        header[21] = 0
        header[22] = UInt8(channels)
        header[23] = 0

        header[24] = (UInt8)(longSampleRate & 0xFF)
        header[25] = (UInt8)((longSampleRate >> 8) & 0xFF)
        header[26] = (UInt8)((longSampleRate >> 16) & 0xFF)
        header[27] = (UInt8)((longSampleRate >> 24) & 0xFF)

        header[28] = (UInt8)(byteRate & 0xFF)
        header[29] = (UInt8)((byteRate >> 8) & 0xFF)
        header[30] = (UInt8)((byteRate >> 16) & 0xFF)
        header[31] = (UInt8)((byteRate >> 24) & 0xFF)

        // block align
        header[32] = UInt8(2 * 16 / 8)
        header[33] = 0

        // bits per sample
        header[34] = 16
        header[35] = 0

        // data
        header[36] = UInt8(ascii: "d")
        header[37] = UInt8(ascii: "a")
        header[38] = UInt8(ascii: "t")
        header[39] = UInt8(ascii: "a")
        header[40] = UInt8(totalAudioLen & 0xFF)
        header[41] = UInt8((totalAudioLen >> 8) & 0xFF)
        header[42] = UInt8((totalAudioLen >> 16) & 0xFF)
        header[43] = UInt8((totalAudioLen >> 24) & 0xFF)

//        guard let writeHandler = try? FileHandle(forWritingTo: output) else { return }
        var data = Data(header)
        data.append(audioData)
        BFLog(message: "createEmptyWAVFile 5")
        do {
            try data.write(to: output, options: .atomicWrite)
            BFLog(message: "createEmptyWAVFile 6 \(data.count)")
        } catch {
            BFLog(message: " write file error \(error)")
        }
    }
}
