|
@@ -15,8 +15,9 @@ import Photos
|
|
|
import UIKit
|
|
|
|
|
|
struct WithDrawModel {
|
|
|
- var type: Int // 0:拖动; 1:预览播放暂停 2: 录音结束
|
|
|
+ var type: Int // 0:拖动; 1:预览播放暂停 2: 录音结束 3: 删除录音
|
|
|
var timestamp: Double
|
|
|
+ var deletedVoices : [(PQVoiceModel, Int)]?
|
|
|
}
|
|
|
|
|
|
public class BFRecordScreenController: BFBaseViewController {
|
|
@@ -38,6 +39,7 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
|
|
|
recordBtn.setTitle(isRecording ? "松手 完成" : "按住 说话", for: .normal)
|
|
|
recordBtn.backgroundColor = UIColor.hexColor(hexadecimal: "#28BE67", alpha: isRecording ? 0.6 : 1)
|
|
|
+ playBtn.isSelected = isRecording
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -88,16 +90,33 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
if let sself = self, let model = model, FileManager.default.fileExists(atPath: model.wavFilePath ?? "") {
|
|
|
// 加入到语音数组里
|
|
|
// TODO: 原逻辑要删除新录音后边的数据, 新逻辑是覆盖则删除
|
|
|
+ model.endTime = sself.currentAssetProgress.seconds
|
|
|
+
|
|
|
+ let newRange = CMTimeRange(start: CMTime(seconds: model.startTime, preferredTimescale: 1000), end: CMTime(seconds: model.endTime, preferredTimescale: 1000))
|
|
|
+
|
|
|
+ var deletedVoices = [(PQVoiceModel, Int)]()
|
|
|
+
|
|
|
for (i, m) in sself.itemModels[sself.currItemModelIndex].voiceStickers.enumerated() {
|
|
|
- if model.endTime > m.startTime && model.endTime <= m.endTime
|
|
|
- || model.startTime <= m.startTime && model.startTime > m.endTime
|
|
|
- {
|
|
|
- sself.itemModels[sself.currItemModelIndex].voiceStickers.remove(at: i)
|
|
|
+ let originRange = CMTimeRange(start: CMTime(seconds: m.startTime, preferredTimescale: 1000), end: CMTime(seconds: m.endTime, preferredTimescale: 1000))
|
|
|
+
|
|
|
+ if CMTimeRangeGetIntersection(originRange, otherRange: newRange).duration.seconds > 0{
|
|
|
+ deletedVoices.append((m, i))
|
|
|
continue
|
|
|
}
|
|
|
}
|
|
|
+ sself.itemModels[sself.currItemModelIndex].voiceStickers.removeAll { m in
|
|
|
+ let originRange = CMTimeRange(start: CMTime(seconds: m.startTime, preferredTimescale: 1000), end: CMTime(seconds: m.endTime, preferredTimescale: 1000))
|
|
|
+ return CMTimeRangeGetIntersection(originRange, otherRange: newRange).duration.seconds > 0
|
|
|
+ }
|
|
|
BFLog(1, message: "添加录音文件:\(model.startTime) -- \(model.endTime)")
|
|
|
-
|
|
|
+ sself.withDrawBtn.setTitle("撤销录制", for: .normal)
|
|
|
+ var event = sself.events.last
|
|
|
+ if event != nil {
|
|
|
+ event!.deletedVoices = deletedVoices
|
|
|
+ sself.events.removeLast()
|
|
|
+ sself.events.append(event!)
|
|
|
+ }
|
|
|
+
|
|
|
sself.itemModels[sself.currItemModelIndex].voiceStickers.append(model)
|
|
|
|
|
|
sself.drawOrUpdateRecordProgessLable()
|
|
@@ -158,6 +177,16 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
|
|
|
return btn
|
|
|
}()
|
|
|
+ lazy var deleteRecordBtn: UIButton = {
|
|
|
+ let btn = UIButton(type: .custom)
|
|
|
+ btn.backgroundColor = .red
|
|
|
+ btn.alpha = 0.5
|
|
|
+ btn.setTitle("删除录制", for: .normal)
|
|
|
+ btn.adjustsImageWhenHighlighted = false
|
|
|
+ btn.addTarget(self, action: #selector(deleteRecorded), for: .touchUpInside)
|
|
|
+ btn.isHidden = true
|
|
|
+ return btn
|
|
|
+ }()
|
|
|
|
|
|
lazy var withDrawBtn: UIButton = {
|
|
|
let btn = UIButton(type: .custom)
|
|
@@ -372,6 +401,7 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
bottomeView.addSubview(progreddL)
|
|
|
// view.addSubview(toolV)
|
|
|
bottomeView.addSubview(recordBtn)
|
|
|
+ bottomeView.addSubview(deleteRecordBtn)
|
|
|
bottomeView.addSubview(withDrawBtn)
|
|
|
// bottomeView.addSubview(changeVoiceBtn)
|
|
|
bottomeView.addSubview(progressThumV)
|
|
@@ -482,6 +512,12 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
make.height.equalTo(42)
|
|
|
make.top.equalTo(withDrawBtn).offset(6)
|
|
|
}
|
|
|
+ deleteRecordBtn.snp.makeConstraints { make in
|
|
|
+ make.left.equalTo(withDrawBtn.snp.right)
|
|
|
+ make.right.equalTo(-65)
|
|
|
+ make.height.equalTo(42)
|
|
|
+ make.top.equalTo(withDrawBtn).offset(6)
|
|
|
+ }
|
|
|
|
|
|
// openCameraBtn.snp.makeConstraints { make in
|
|
|
// make.right.equalToSuperview().offset(-12)
|
|
@@ -592,16 +628,34 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
audioSettingView.isHidden = false
|
|
|
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ @objc func deleteRecorded(){
|
|
|
+ if isStopAtRecordRange != -1, isStopAtRecordRange < itemModels[currItemModelIndex].voiceStickers.count {
|
|
|
+ let model = itemModels[currItemModelIndex].voiceStickers[isStopAtRecordRange]
|
|
|
+ itemModels[currItemModelIndex].voiceStickers.remove(at: isStopAtRecordRange)
|
|
|
+ drawOrUpdateRecordProgessLable()
|
|
|
+ searchStopAtRecordRange()
|
|
|
+ events.append(WithDrawModel(type: 3, timestamp: self.currentAssetProgress.seconds, deletedVoices: [(model, isStopAtRecordRange)]))
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
@objc func startRecord() {
|
|
|
BFLog(1, message: "start \(UIControl.Event.touchDown)")
|
|
|
|
|
|
+ // 停止进度条滚动
|
|
|
let point = progressThumV.progressView.contentOffset
|
|
|
progressThumV.progressView.setContentOffset(point, animated: false)
|
|
|
|
|
|
- isRecording = true
|
|
|
pause()
|
|
|
+ isRecording = true
|
|
|
|
|
|
+ let model = PQVoiceModel()
|
|
|
+ model.startTime = currentAssetProgress.seconds
|
|
|
+ model.volume = 100
|
|
|
+ recorderManager.voiceModel = model
|
|
|
+ recorderManager.startRecord(index: 1)
|
|
|
+
|
|
|
movie?.startProcessing()
|
|
|
assetPlayer?.volume = 0
|
|
|
assetPlayer?.play()
|
|
@@ -611,11 +665,7 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
avatarView.beginRecord()
|
|
|
}
|
|
|
|
|
|
- let model = PQVoiceModel()
|
|
|
- model.startTime = currentAssetProgress.seconds
|
|
|
- model.volume = 100
|
|
|
- recorderManager.voiceModel = model
|
|
|
- recorderManager.startRecord(index: 1)
|
|
|
+
|
|
|
|
|
|
// 添加撤销记录点
|
|
|
events.append(WithDrawModel(type: 2, timestamp: model.startTime))
|
|
@@ -639,14 +689,13 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
DispatchQueue.global().async {
|
|
|
self.speechTranscriberUtil?.endTranscriber()
|
|
|
}
|
|
|
- playBtn.isSelected = true
|
|
|
+// playBtn.isSelected = true
|
|
|
// 存储录音
|
|
|
isRecording = false
|
|
|
+ pause()
|
|
|
|
|
|
- recorderManager.voiceModel?.endTime = currentAssetProgress.seconds
|
|
|
recorderManager.endRecord()
|
|
|
|
|
|
- pause()
|
|
|
if !avatarView.isHidden {
|
|
|
avatarView.endRecord()
|
|
|
}
|
|
@@ -670,10 +719,35 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
}) {
|
|
|
let model = itemModels[currItemModelIndex].voiceStickers[modelIndex]
|
|
|
itemModels[currItemModelIndex].voiceStickers.remove(at: modelIndex)
|
|
|
+
|
|
|
+ var tuples = action.deletedVoices
|
|
|
+ if tuples != nil, tuples!.count > 0 {
|
|
|
+ tuples!.sort { tuple1, tuple2 in
|
|
|
+ tuple1.1 < tuple2.1
|
|
|
+ }
|
|
|
+ tuples?.forEach({ tuple in
|
|
|
+ itemModels[currItemModelIndex].voiceStickers.insert(tuple.0, at: tuple.1)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
drawOrUpdateRecordProgessLable()
|
|
|
jumpTime = model.startTime
|
|
|
}
|
|
|
- } else {}
|
|
|
+ } else if action.type == 3 {
|
|
|
+ // 删除录音
|
|
|
+ var tuples = action.deletedVoices
|
|
|
+ if tuples != nil, tuples!.count > 0 {
|
|
|
+ tuples!.sort { tuple1, tuple2 in
|
|
|
+ tuple1.1 < tuple2.1
|
|
|
+ }
|
|
|
+ tuples?.forEach({ tuple in
|
|
|
+ itemModels[currItemModelIndex].voiceStickers.insert(tuple.0, at: tuple.1)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ drawOrUpdateRecordProgessLable()
|
|
|
+ } else {
|
|
|
+
|
|
|
+ }
|
|
|
events.removeLast()
|
|
|
let dur = itemModels[currItemModelIndex].materialDuraion
|
|
|
if dur > 0 {
|
|
@@ -683,6 +757,13 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
hadPrepareToPlayRecord = false
|
|
|
progressThumV.progress = jumpTime
|
|
|
}
|
|
|
+
|
|
|
+ if let event = events.last, event.type == 2{
|
|
|
+ withDrawBtn.setTitle("撤销录制", for: .normal)
|
|
|
+ }else{
|
|
|
+ withDrawBtn.setTitle("撤销", for: .normal)
|
|
|
+ }
|
|
|
+ searchStopAtRecordRange()
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -697,6 +778,7 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
searchStopAtRecordRange()
|
|
|
} else {
|
|
|
events.append(WithDrawModel(type: 1, timestamp: currentAssetProgress.seconds))
|
|
|
+ withDrawBtn.setTitle("撤销", for: .normal)
|
|
|
play()
|
|
|
}
|
|
|
}
|
|
@@ -724,10 +806,12 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
hadPrepareToPlayRecord = false
|
|
|
BFLog(1, message: isDragingProgressSlder ? "drag false" : "drag tr")
|
|
|
searchStopAtRecordRange()
|
|
|
+ withDrawBtn.setTitle("撤销", for: .normal)
|
|
|
+
|
|
|
}
|
|
|
|
|
|
func searchStopAtRecordRange() {
|
|
|
- // TODO: 判断是否停止录音区间,是则删除相关录音,画笔,头像,字幕
|
|
|
+ // TODO: 滑动,播放暂停,撤销时,判断是否停止录音区间,是则删除相关录音,画笔,头像,字幕
|
|
|
let elems = itemModels[currItemModelIndex].voiceStickers.enumerated().filter { elem in
|
|
|
elem.1.startTime <= self.currentAssetProgress.seconds && elem.1.endTime > self.currentAssetProgress.seconds
|
|
|
}
|
|
@@ -735,11 +819,17 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
|
|
|
if elems.count > 0 {
|
|
|
// TODO: 停在了录音区间,显示删除按钮
|
|
|
+ deleteRecordBtn.isHidden = false
|
|
|
+ recordBtn.isHidden = true
|
|
|
+
|
|
|
isStopAtRecordRange = elems.first!.0
|
|
|
- BFLog(1, message: "停在了录音区间 里")
|
|
|
+ BFLog(1, message: "停在了录音区间里 \(isStopAtRecordRange)")
|
|
|
} else {
|
|
|
+ deleteRecordBtn.isHidden = true
|
|
|
+ recordBtn.isHidden = false
|
|
|
+
|
|
|
isStopAtRecordRange = -1
|
|
|
- BFLog(1, message: "停在了录音区间 外")
|
|
|
+ BFLog(1, message: "停在了录音区间外 \(isStopAtRecordRange)")
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -971,8 +1061,8 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
avplayerTimeObserver = assetPlayer?.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 100), queue: DispatchQueue.global()) { [weak self] time in
|
|
|
// 进度监控
|
|
|
|
|
|
- self?.currentAssetProgress = time
|
|
|
- BFLog(1, message: "curr:\(CMTimeGetSeconds(time))")
|
|
|
+ self?.currentAssetProgress = CMTime(seconds: time.seconds, preferredTimescale: 1000)
|
|
|
+ BFLog(1, message: "curr:\(CMTimeGetSeconds(self?.currentAssetProgress ?? .zero))")
|
|
|
if CMTimeGetSeconds(item.duration) > 0 {
|
|
|
DispatchQueue.main.async { [weak self] in
|
|
|
self?.progreddL.text = String(format: "%@", CMTimeGetSeconds(time).formatDurationToHMS())
|
|
@@ -1022,12 +1112,12 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
|
|
|
func changeProgress(progress: Float) {
|
|
|
if let duration = assetPlayer?.currentItem?.duration {
|
|
|
- currentAssetProgress = CMTime(value: CMTimeValue(progress * Float(CMTimeGetSeconds(duration)) * 100), timescale: 100)
|
|
|
+ currentAssetProgress = CMTime(value: CMTimeValue(progress * Float(CMTimeGetSeconds(duration)) * 1000), timescale: 1000)
|
|
|
DispatchQueue.main.async { [weak self] in
|
|
|
self!.progreddL.text = String(format: "%@", CMTimeGetSeconds(self!.currentAssetProgress).formatDurationToHMS())
|
|
|
}
|
|
|
|
|
|
- assetPlayer!.seek(to: currentAssetProgress, toleranceBefore: CMTime(value: 1, timescale: 1_000_000), toleranceAfter: CMTime(value: 1, timescale: 1_000_000)) { _ in
|
|
|
+ assetPlayer!.seek(to: currentAssetProgress, toleranceBefore: CMTime(value: 1, timescale: 1000), toleranceAfter: CMTime(value: 1, timescale: 1000)) { _ in
|
|
|
}
|
|
|
}
|
|
|
}
|