//
//  ConvertPcmToWavTool.swift
//  Runner
//
//  Created by 中道 on 2022/5/9.
//

import Foundation

class ConvertPcmToWaveTool {

   // 采样率
   private var mSampleRate = 24000
   
   // 声道
   private var mChannel = 1
   
   func pcmToWav(inFileName: String, outFileName: String) {
       
       guard let input: URL = URL(string: inFileName) else { return }
       guard let output: URL = URL(string: outFileName) else { return }
       
       var totalAudioLen: Int64
       var totalDataLen: Int64
       let longSampleRate: Int64 = Int64(mSampleRate)
       
       let channels = 1
       let byteRate: Int64 = Int64(16 * mSampleRate * channels / 8)
       
       totalAudioLen = Int64(inFileName.getFileSize())
       print("---------totalAudioLen---------\(totalAudioLen)")
       totalDataLen = totalAudioLen + 36
       
       writewaveFileHeader(output: output, totalAudioLen: totalAudioLen, totalDataLen: totalDataLen, longSampleRate: longSampleRate, channels: channels, byteRate: byteRate)
       
       guard let readHandler = try? FileHandle(forReadingFrom: input) else { return }
       guard let writeHandler = try? FileHandle(forWritingTo: output) else { return }
       
        // 文件头占44字节，偏移后才写入pcm数据
       writeHandler.seek(toFileOffset: 44)
       
       let data = readHandler.readDataToEndOfFile()
       
       writeHandler.write(data)
   
       print("---getFileSize----\(outFileName.getFileSize())---")
   }
   
   func writewaveFileHeader(output: URL, totalAudioLen: Int64, totalDataLen: Int64, longSampleRate: Int64, channels: Int, byteRate: Int64) {
       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 }
       let data = Data(header)
       writeHandler.write(data)
       
   }

}

extension String {
   
   /// 计算文件夹大小(有单文件计算)
   func getFileSize() -> UInt64  {
       var size: UInt64 = 0
       let fileManager = FileManager.default
       var isDir: ObjCBool = false
       let isExists = fileManager.fileExists(atPath: self, isDirectory: &isDir)
       // 判断文件存在
       if isExists {
           // 是否为文件夹
           if isDir.boolValue {
               // 迭代器 存放文件夹下的所有文件名
               let enumerator = fileManager.enumerator(atPath: self)
               for subPath in enumerator! {
                   // 获得全路径
                   let fullPath = self.appending("/\(subPath)")
                   do {
                       let attr = try fileManager.attributesOfItem(atPath: fullPath)
                       size += attr[FileAttributeKey.size] as! UInt64
                   } catch  {
                       print("error :\(error)")
                   }
               }
           } else {    // 单文件
               do {
                   let attr = try fileManager.attributesOfItem(atPath: self)
                   size += attr[FileAttributeKey.size] as! UInt64
                   
               } catch  {
                   print("error :\(error)")
               }
           }
       }
       return size
   }
}
