PQVoiceModel.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. //
  2. // PQVoiceModel.swift
  3. // PQSpeed
  4. //
  5. // Created by ak on 2020/8/18.
  6. // Copyright © 2020 BytesFlow. All rights reserved.
  7. //
  8. import Foundation
  9. enum voiceStatue: Int {
  10. case isLoading = 0 // 加载中
  11. case isPlaying = 1 // 播放中
  12. case isNormal = 2 // 正常状态
  13. case isSelected = 3 // 选中状态,有红框 字红色 ,别的都没有
  14. }
  15. class PQVoiceModel: NSObject, NSCopying {
  16. public var name: String = ""
  17. // 对应接口的 KEY
  18. public var voice: String = ""
  19. public var cateId: Int = 0
  20. // 性别
  21. public var gender: Int = 0
  22. public var avatarUrl: String = ""
  23. public var channel: String = "aliyun" // aliyun , azure
  24. // 是否为精品
  25. public var qualityFlag: Int = 0
  26. // 微软语音设置
  27. // public var azureStyleConfig: [PQAzureStyleModel] = Array()
  28. // 声音文件沙盒位置 是 URI
  29. public var wavFilePath: String!
  30. // 是否收藏
  31. public var isFavorite: Bool = false
  32. // 是否在加载状态 是否在播放状态f
  33. public var voiceStatue: voiceStatue = .isNormal
  34. // 收藏 ID
  35. public var favoriteId: Int = 0
  36. public var speedRate: Float = 1.0
  37. public var pitchRate: Float = 0
  38. public var azureStyle: String = "general"
  39. var isSelected: Bool = false // 是否被选中
  40. var isPlaying: Bool = false // 是否在播放
  41. var itemWidth: CGFloat = 0 // 元素宽度
  42. var materialUrl: String? // 播放地址
  43. var localPath: String? // 本地存储地址
  44. var duration: String? // 时长
  45. var currentTime: Float64? // 当前已播放时长
  46. var uniqueId: Int = 0 // 背景音乐ID
  47. var materialId: String? // 保存发音人后素材IDmaterialUrl
  48. var volume: Int = 0 // 0-100 素材音量
  49. var startTime: Float64 = 0 // 开始时间
  50. var endTime: Float64 = 0 // 结束时间
  51. var createTimestamp: Int64 = 0 // 创建时间
  52. var voiceType: String = VOICETYPT.PRODUCE.rawValue // 音乐类型
  53. var accompanimentPath: String? // 伴奏地址
  54. var musicId: String? // 音乐ID
  55. var musicLabels: String? // 标签
  56. var musicName: String? // 歌名
  57. var musicPath: String? // 音乐地址
  58. var musicSinger: String? // 歌手
  59. var originType: Int = 1 // 音乐来源: 1上传, 2爬取
  60. var sortNum: Int = 0 // 排序值
  61. var vodAccompanimentMediaId: String? // 伴奏vod mediaId
  62. var vodMusicMediaId: String? // 音乐vod mediaId
  63. // add by ak json 结构化数据传值使用
  64. var wavfileDuration: Float64 = 0
  65. var selectVoiceType: Int = 1 // 选择的声音类型,1:原声 ,2:背景声
  66. // 卡点视频-分类信息
  67. var tagsInfo: PQStuckPointMusicTagsModel?
  68. // 卡点视频-卡点时间数据
  69. var rhythmSdata: [PQStuckPointTimesModel] = Array<PQStuckPointTimesModel>.init()
  70. // 卡点视频-默认卡点速度(1:快节奏,2:适中,3:慢节奏) ,
  71. var speed: Int = 2
  72. // 卡点视频-卡点音乐入点
  73. var rhythmMusicIn: Float64 = 0
  74. // 卡点视频-卡点音乐出点
  75. var rhythmMusicOut: Float64 = 0
  76. // 卡点视频-源项目ID(从那个项目做同款)
  77. var originProjectId: String?
  78. func copy(with _: NSZone? = nil) -> Any {
  79. let voice = PQVoiceModel()
  80. voice.name = name
  81. voice.channel = channel
  82. voice.azureStyle = azureStyle
  83. voice.voice = self.voice
  84. voice.cateId = cateId
  85. voice.gender = gender
  86. voice.duration = duration
  87. voice.avatarUrl = avatarUrl
  88. voice.wavFilePath = wavFilePath
  89. voice.isFavorite = isFavorite
  90. voice.isSelected = isSelected
  91. voice.voiceStatue = voiceStatue
  92. voice.speedRate = speedRate
  93. voice.pitchRate = pitchRate
  94. voice.qualityFlag = qualityFlag
  95. // voice.azureStyleConfig = azureStyleConfig
  96. // ui 使用
  97. voice.isSelected = isSelected
  98. voice.isPlaying = isPlaying
  99. voice.itemWidth = itemWidth
  100. voice.materialUrl = materialUrl
  101. voice.localPath = localPath
  102. voice.duration = duration
  103. voice.currentTime = currentTime
  104. voice.uniqueId = uniqueId
  105. voice.volume = volume
  106. voice.startTime = startTime
  107. voice.endTime = endTime
  108. voice.createTimestamp = createTimestamp
  109. voice.voiceType = voiceType
  110. voice.accompanimentPath = accompanimentPath
  111. voice.musicId = musicId
  112. voice.musicLabels = musicLabels
  113. voice.musicName = musicName
  114. voice.musicPath = musicPath
  115. voice.musicSinger = musicSinger
  116. voice.originType = originType
  117. voice.sortNum = sortNum
  118. voice.vodAccompanimentMediaId = vodAccompanimentMediaId
  119. voice.vodMusicMediaId = vodMusicMediaId
  120. return voice
  121. }
  122. override init() {
  123. super.init()
  124. }
  125. init(jsonDict: [String: Any]) {
  126. super.init()
  127. if jsonDict.keys.contains("name"), "\(jsonDict["name"] ?? "")" != "<null>" {
  128. name = "\(jsonDict["name"] ?? "")"
  129. }
  130. if jsonDict.keys.contains("cateName"), "\(jsonDict["cateName"] ?? "")" != "<null>" {
  131. name = "\(jsonDict["cateName"] ?? "")"
  132. }
  133. if jsonDict.keys.contains("coverUrl") {
  134. avatarUrl = "\(jsonDict["coverUrl"] ?? "")"
  135. }
  136. if jsonDict.keys.contains("avatarUrl") {
  137. avatarUrl = "\(jsonDict["avatarUrl"] ?? "")"
  138. }
  139. if jsonDict.keys.contains("coverImgPath") {
  140. avatarUrl = "\(jsonDict["coverImgPath"] ?? "")"
  141. }
  142. if jsonDict.keys.contains("bgmId") {
  143. uniqueId = Int("\(jsonDict["bgmId"] ?? "0")") ?? 0
  144. }
  145. if jsonDict.keys.contains("gender") {
  146. gender = Int("\(jsonDict["gender"] ?? "0")") ?? 0
  147. }
  148. if jsonDict.keys.contains("id") {
  149. uniqueId = Int("\(jsonDict["id"] ?? "0")") ?? 0
  150. }
  151. if jsonDict.keys.contains("cateId") {
  152. cateId = Int("\(jsonDict["cateId"] ?? "0")") ?? 0
  153. }
  154. if jsonDict.keys.contains("cid") {
  155. cateId = Int("\(jsonDict["cid"] ?? "0")") ?? 0
  156. }
  157. if jsonDict.keys.contains("createTimestamp") {
  158. createTimestamp = Int64("\(jsonDict["createTimestamp"] ?? "0")") ?? 0
  159. }
  160. if name.count > 0 {
  161. itemWidth = sizeWithText(text: name, font: UIFont.systemFont(ofSize: 14, weight: .semibold), size: CGSize(width: cDefaultMargin * 10, height: cDefaultMargin * 4)).width + cDefaultMargin * 3
  162. }
  163. if jsonDict.keys.contains("favoriteStatus") {
  164. isFavorite = "\(jsonDict["favoriteStatus"] ?? "0")" == "1"
  165. }
  166. if jsonDict.keys.contains("materialUrl") {
  167. materialUrl = "\(jsonDict["materialUrl"] ?? "")"
  168. }
  169. if jsonDict.keys.contains("duration") {
  170. duration = "\(jsonDict["duration"] ?? "")"
  171. if (Float64("\(duration ?? "0")") ?? 0) < 1_000_000 {
  172. duration = "\(Float64("\(duration ?? "0")") ?? 0)"
  173. } else {
  174. duration = "\((Float64("\(duration ?? "0")") ?? 0) / 1_000_000)"
  175. }
  176. }
  177. if jsonDict.keys.contains("accompanimentPath") {
  178. accompanimentPath = "\(jsonDict["accompanimentPath"] ?? "")"
  179. }
  180. if jsonDict.keys.contains("musicId") {
  181. musicId = "\(jsonDict["musicId"] ?? "")"
  182. }
  183. if jsonDict.keys.contains("musicLabels") {
  184. musicLabels = "\(jsonDict["musicLabels"] ?? "")"
  185. }
  186. if jsonDict.keys.contains("musicName") {
  187. musicName = "\(jsonDict["musicName"] ?? "")"
  188. }
  189. if jsonDict.keys.contains("musicPath") {
  190. musicPath = "\(jsonDict["musicPath"] ?? "")"
  191. }
  192. if jsonDict.keys.contains("coverMusicPath") {
  193. musicPath = "\(jsonDict["coverMusicPath"] ?? "")"
  194. }
  195. if jsonDict.keys.contains("musicSinger"), "\(jsonDict["musicSinger"] ?? "")" != "<null>" {
  196. musicSinger = "\(jsonDict["musicSinger"] ?? "")"
  197. }
  198. if jsonDict.keys.contains("author"), "\(jsonDict["author"] ?? "")" != "<null>" {
  199. musicSinger = "\(jsonDict["author"] ?? "")"
  200. }
  201. if jsonDict.keys.contains("originType") {
  202. originType = Int("\(jsonDict["originType"] ?? "0")") ?? 0
  203. }
  204. if jsonDict.keys.contains("sortNum") {
  205. sortNum = Int("\(jsonDict["sortNum"] ?? "0")") ?? 0
  206. }
  207. if jsonDict.keys.contains("vodAccompanimentMediaId") {
  208. vodAccompanimentMediaId = "\(jsonDict["vodAccompanimentMediaId"] ?? "")"
  209. }
  210. if jsonDict.keys.contains("vodMusicMediaId") {
  211. vodAccompanimentMediaId = "\(jsonDict["vodMusicMediaId"] ?? "")"
  212. }
  213. if jsonDict.keys.contains("musicTagInfos") {
  214. let musicTagInfos = jsonDict["musicTagInfos"] as? [String: Any]
  215. if musicTagInfos != nil, (musicTagInfos?.keys.count ?? 0) > 0 {
  216. tagsInfo = PQStuckPointMusicTagsModel(jsonDict: musicTagInfos!)
  217. }
  218. }
  219. if jsonDict.keys.contains("rhythmSdata"), "\(jsonDict["rhythmSdata"] ?? "")".count > 0, "\(jsonDict["rhythmSdata"] ?? "")" != "<null>" {
  220. let tempArr = jsonStringToArray(jsonString: "\(jsonDict["rhythmSdata"] ?? "")")
  221. if tempArr != nil, (tempArr?.count ?? 0) > 0 {
  222. tempArr?.forEach { sdata in
  223. let tempTimesModel: PQStuckPointTimesModel = PQStuckPointTimesModel(jsonDict: (sdata as? [String: Any]) ?? [:])
  224. rhythmSdata.append(tempTimesModel)
  225. }
  226. }
  227. }
  228. if jsonDict.keys.contains("suggestRhythmStart") {
  229. startTime = (Float64("\(jsonDict["suggestRhythmStart"] ?? "0")") ?? 0) / 1_000_000
  230. }
  231. if jsonDict.keys.contains("suggestRhythmEnd") {
  232. endTime = (Float64("\(jsonDict["suggestRhythmEnd"] ?? "0")") ?? 0) / 1_000_000
  233. }
  234. if jsonDict.keys.contains("speed"), "\(jsonDict["speed"] ?? "")" != "<null>" {
  235. speed = Int("\(jsonDict["speed"] ?? "2")") ?? 2
  236. }
  237. if jsonDict.keys.contains("rhythmMusicIn") {
  238. rhythmMusicIn = (Float64("\(jsonDict["rhythmMusicIn"] ?? "0")") ?? 0) / 1_000_000
  239. }
  240. if jsonDict.keys.contains("rhythmMusicOut") {
  241. rhythmMusicOut = (Float64("\(jsonDict["rhythmMusicOut"] ?? "0")") ?? 0) / 1_000_000
  242. }
  243. if jsonDict.keys.contains("originProjectId"), "\(jsonDict["originProjectId"] ?? "")" != "<null>" {
  244. originProjectId = "\(jsonDict["originProjectId"] ?? "")"
  245. }
  246. if jsonDict.keys.contains("projectId"), "\(jsonDict["projectId"] ?? "")" != "<null>" {
  247. originProjectId = "\(jsonDict["projectId"] ?? "")"
  248. }
  249. }
  250. /// 计算卡点时长 策略1 :
  251. /// - Parameters:
  252. /// - videoCount: 视频个数
  253. /// - imageCount: 图片个数
  254. /// - Returns: <#description#>
  255. func stuckPointCuttingTime(videoCount: Int, imageCount: Int, totalDuration: Float64) -> Float64 {
  256. if totalDuration <= 0 {
  257. return 0
  258. }
  259. // 默认比例
  260. let rate: Float64 = 1.5
  261. // 音乐最大时长
  262. let MaxM: Float64 = 40
  263. // 音乐最小时长
  264. let MinM: Float64 = 10
  265. // 视频个数
  266. // var V1: Float64 = Float64(videoCount)
  267. // 图片个数
  268. let V2: Float64 = Float64(imageCount)
  269. // 视频总时长
  270. let V1T: Float64 = totalDuration - V2
  271. // 推荐音乐时长
  272. var M: Float64 = endTime - startTime
  273. // 音频段数
  274. // let MC: Float64 = Float64(rhythmSdata.first?.pointTimes.count ?? 1)
  275. // 档位时长平均值
  276. // let MST: Float64 = (Float64(duration ?? "0") ?? 0) / MC
  277. // 从推荐点位开始speed*V2 的点位个数的时长/V2
  278. let startS: Float64 = Float64(Double(rhythmSdata.first?.pointTimes.first ?? 0) / 1_000_000.0)
  279. var endS: Float64 = Float64(Double(rhythmSdata.first?.pointTimes.last ?? 0) / 1_000_000.0)
  280. if V2 > 0, speed > 0, Float64(rhythmSdata.first?.pointTimes.count ?? 0) > (V2 * Float64(speed) + 2) {
  281. endS = Float64(Double(rhythmSdata.first?.pointTimes[Int(V2 * Float64(speed) + 2)] ?? 0) / 1_000_000.0)
  282. }
  283. let MST: Float64 = V2 <= 0 ? 0 : (endS - startS) / V2
  284. if (V2 * MST + V1T / 2) >= MaxM {
  285. M = MaxM
  286. } else if (V2 * MST + V1T / 2) >= MinM && MaxM > (V2 * MST + V1T / 2) {
  287. M = V2 * MST + V1T / 2
  288. } else if (V2 * MST + V1T / 2) <= MinM && (V2 * MST + V1T) * rate >= MinM {
  289. M = (V2 * MST + V1T) * rate
  290. } else if (V2 * MST + V1T) * rate < MinM {
  291. M = MinM
  292. }
  293. // 限制卡点时长最大值不能超过duration
  294. if (M + startTime) > endTime {
  295. M = endTime - startTime
  296. }else if (M + startTime) > (Float64(duration ?? "0") ?? 0) {
  297. M = (Float64(duration ?? "0") ?? 0) - startTime
  298. }
  299. BFLog(message: "计算当前裁剪时长:\(M),开始时间:\(startTime),结束时间:\(endTime),总时长:\(Float64(duration ?? "0") ?? 0)")
  300. return M
  301. }
  302. }