mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit 'c8a6252d461072eda0dd3b23e58e2008f5421213'
This commit is contained in:
commit
935a6e32da
@ -83,20 +83,23 @@ private final class AnimatedStickerFrame {
|
||||
let width: Int
|
||||
let height: Int
|
||||
let bytesPerRow: Int
|
||||
let index: Int
|
||||
let isLastFrame: Bool
|
||||
|
||||
init(data: Data, type: AnimationRendererFrameType, width: Int, height: Int, bytesPerRow: Int, isLastFrame: Bool) {
|
||||
init(data: Data, type: AnimationRendererFrameType, width: Int, height: Int, bytesPerRow: Int, index: Int, isLastFrame: Bool) {
|
||||
self.data = data
|
||||
self.type = type
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.bytesPerRow = bytesPerRow
|
||||
self.index = index
|
||||
self.isLastFrame = isLastFrame
|
||||
}
|
||||
}
|
||||
|
||||
private protocol AnimatedStickerFrameSource: class {
|
||||
var frameRate: Int { get }
|
||||
var frameCount: Int { get }
|
||||
|
||||
func takeFrame() -> AnimatedStickerFrame
|
||||
}
|
||||
@ -110,6 +113,8 @@ private final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
|
||||
let bytesPerRow: Int
|
||||
let height: Int
|
||||
let frameRate: Int
|
||||
let frameCount: Int
|
||||
private var frameIndex: Int
|
||||
private let initialOffset: Int
|
||||
private var offset: Int
|
||||
var decodeBuffer: Data
|
||||
@ -125,21 +130,26 @@ private final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
|
||||
var height = 0
|
||||
var bytesPerRow = 0
|
||||
var frameRate = 0
|
||||
var frameCount = 0
|
||||
|
||||
if !self.data.withUnsafeBytes({ (bytes: UnsafePointer<UInt8>) -> Bool in
|
||||
var frameRateValue: Int32 = 0
|
||||
memcpy(&frameRateValue, bytes.advanced(by: offset), 4)
|
||||
frameRate = Int(frameRateValue)
|
||||
offset += 4
|
||||
var frameCountValue: Int32 = 0
|
||||
var widthValue: Int32 = 0
|
||||
var heightValue: Int32 = 0
|
||||
var bytesPerRowValue: Int32 = 0
|
||||
memcpy(&frameRateValue, bytes.advanced(by: offset), 4)
|
||||
offset += 4
|
||||
memcpy(&frameCountValue, bytes.advanced(by: offset), 4)
|
||||
offset += 4
|
||||
memcpy(&widthValue, bytes.advanced(by: offset), 4)
|
||||
offset += 4
|
||||
memcpy(&heightValue, bytes.advanced(by: offset), 4)
|
||||
offset += 4
|
||||
memcpy(&bytesPerRowValue, bytes.advanced(by: offset), 4)
|
||||
offset += 4
|
||||
frameRate = Int(frameRateValue)
|
||||
frameCount = Int(frameCountValue)
|
||||
width = Int(widthValue)
|
||||
height = Int(heightValue)
|
||||
bytesPerRow = Int(bytesPerRowValue)
|
||||
@ -154,7 +164,9 @@ private final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.frameRate = frameRate
|
||||
self.frameCount = frameCount
|
||||
|
||||
self.frameIndex = 0
|
||||
self.initialOffset = offset
|
||||
self.offset = offset
|
||||
|
||||
@ -178,6 +190,8 @@ private final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
|
||||
let decodeBufferLength = self.decodeBuffer.count
|
||||
let frameBufferLength = self.frameBuffer.count
|
||||
|
||||
let frameIndex = self.frameIndex
|
||||
|
||||
self.data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
|
||||
var frameLength: Int32 = 0
|
||||
memcpy(&frameLength, bytes.advanced(by: self.offset), 4)
|
||||
@ -208,9 +222,11 @@ private final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
|
||||
}
|
||||
}
|
||||
|
||||
self.frameIndex += 1
|
||||
self.offset += Int(frameLength)
|
||||
if self.offset == dataLength {
|
||||
isLastFrame = true
|
||||
self.frameIndex = 0
|
||||
self.offset = self.initialOffset
|
||||
self.frameBuffer.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
memset(bytes, 0, frameBufferLength)
|
||||
@ -218,7 +234,7 @@ private final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
|
||||
}
|
||||
}
|
||||
|
||||
return AnimatedStickerFrame(data: frameData!, type: .yuva, width: self.width, height: self.height, bytesPerRow: self.bytesPerRow, isLastFrame: isLastFrame)
|
||||
return AnimatedStickerFrame(data: frameData!, type: .yuva, width: self.width, height: self.height, bytesPerRow: self.bytesPerRow, index: frameIndex, isLastFrame: isLastFrame)
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,7 +244,7 @@ private final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource
|
||||
private let width: Int
|
||||
private let height: Int
|
||||
private let bytesPerRow: Int
|
||||
private let frameCount: Int
|
||||
let frameCount: Int
|
||||
let frameRate: Int
|
||||
private var currentFrame: Int
|
||||
private let animation: LottieInstance
|
||||
@ -263,7 +279,7 @@ private final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource
|
||||
memset(bytes, 0, self.bytesPerRow * self.height)
|
||||
self.animation.renderFrame(with: Int32(frameIndex), into: bytes, width: Int32(self.width), height: Int32(self.height), bytesPerRow: Int32(self.bytesPerRow))
|
||||
}
|
||||
return AnimatedStickerFrame(data: frameData, type: .argb, width: self.width, height: self.height, bytesPerRow: self.bytesPerRow, isLastFrame: frameIndex == self.frameCount)
|
||||
return AnimatedStickerFrame(data: frameData, type: .argb, width: self.width, height: self.height, bytesPerRow: self.bytesPerRow, index: frameIndex, isLastFrame: frameIndex == self.frameCount)
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,6 +314,18 @@ private final class AnimatedStickerFrameQueue {
|
||||
}
|
||||
}
|
||||
|
||||
public struct AnimatedStickerStatus: Equatable {
|
||||
public let playing: Bool
|
||||
public let duration: Double
|
||||
public let timestamp: Double
|
||||
|
||||
public init(playing: Bool, duration: Double, timestamp: Double) {
|
||||
self.playing = playing
|
||||
self.duration = duration
|
||||
self.timestamp = timestamp
|
||||
}
|
||||
}
|
||||
|
||||
final class AnimatedStickerNode: ASDisplayNode {
|
||||
private let queue: Queue
|
||||
private var account: Account?
|
||||
@ -319,6 +347,11 @@ final class AnimatedStickerNode: ASDisplayNode {
|
||||
private var isPlaying: Bool = false
|
||||
private var playbackMode: AnimatedStickerPlaybackMode = .loop
|
||||
|
||||
private let playbackStatus = Promise<AnimatedStickerStatus>()
|
||||
public var status: Signal<AnimatedStickerStatus, NoError> {
|
||||
return self.playbackStatus.get()
|
||||
}
|
||||
|
||||
var visibility = false {
|
||||
didSet {
|
||||
if self.visibility != oldValue {
|
||||
@ -440,7 +473,10 @@ final class AnimatedStickerNode: ASDisplayNode {
|
||||
})
|
||||
timerHolder.swap(nil)?.invalidate()
|
||||
|
||||
let timer = SwiftSignalKit.Timer(timeout: 1.0 / Double(frameSource.frameRate), repeat: true, completion: {
|
||||
let duration: Double = frameSource.frameRate > 0 ? Double(frameSource.frameCount) / Double(frameSource.frameRate) : 0
|
||||
let frameRate = frameSource.frameRate
|
||||
|
||||
let timer = SwiftSignalKit.Timer(timeout: 1.0 / Double(frameRate), repeat: true, completion: {
|
||||
let maybeFrame = frameQueue.syncWith { frameQueue in
|
||||
return frameQueue.take()
|
||||
}
|
||||
@ -449,6 +485,7 @@ final class AnimatedStickerNode: ASDisplayNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.renderer?.render(queue: strongSelf.queue, width: frame.width, height: frame.height, bytesPerRow: frame.bytesPerRow, data: frame.data, type: frame.type, completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -458,10 +495,14 @@ final class AnimatedStickerNode: ASDisplayNode {
|
||||
strongSelf.started()
|
||||
}
|
||||
})
|
||||
|
||||
if case .once = strongSelf.playbackMode, frame.isLastFrame {
|
||||
strongSelf.stop()
|
||||
strongSelf.isPlaying = false
|
||||
}
|
||||
|
||||
let timestamp: Double = frameRate > 0 ? Double(frame.index) / Double(frameRate) : 0
|
||||
strongSelf.playbackStatus.set(.single(AnimatedStickerStatus(playing: strongSelf.isPlaying, duration: duration, timestamp: timestamp)))
|
||||
}
|
||||
}
|
||||
frameQueue.with { frameQueue in
|
||||
@ -502,6 +543,8 @@ final class AnimatedStickerNode: ASDisplayNode {
|
||||
})
|
||||
timerHolder.swap(nil)?.invalidate()
|
||||
|
||||
let duration: Double = frameSource.frameRate > 0 ? Double(frameSource.frameCount) / Double(frameSource.frameRate) : 0
|
||||
|
||||
let maybeFrame = frameQueue.syncWith { frameQueue in
|
||||
return frameQueue.take()
|
||||
}
|
||||
@ -510,6 +553,7 @@ final class AnimatedStickerNode: ASDisplayNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.renderer?.render(queue: strongSelf.queue, width: frame.width, height: frame.height, bytesPerRow: frame.bytesPerRow, data: frame.data, type: frame.type, completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -519,10 +563,8 @@ final class AnimatedStickerNode: ASDisplayNode {
|
||||
strongSelf.started()
|
||||
}
|
||||
})
|
||||
if case .once = strongSelf.playbackMode, frame.isLastFrame {
|
||||
strongSelf.stop()
|
||||
strongSelf.isPlaying = false
|
||||
}
|
||||
|
||||
strongSelf.playbackStatus.set(.single(AnimatedStickerStatus(playing: false, duration: duration, timestamp: 0.0)))
|
||||
}
|
||||
}
|
||||
frameQueue.with { frameQueue in
|
||||
|
@ -196,7 +196,9 @@ func experimentalConvertCompressedLottieToCombinedMp4(data: Data, size: CGSize,
|
||||
var currentFrame: Int32 = 0
|
||||
|
||||
var fps: Int32 = player.frameRate
|
||||
var frameCount: Int32 = player.frameCount
|
||||
let _ = fileContext.write(&fps, count: 4)
|
||||
let _ = fileContext.write(&frameCount, count: 4)
|
||||
var widthValue: Int32 = Int32(size.width)
|
||||
var heightValue: Int32 = Int32(size.height)
|
||||
var bytesPerRowValue: Int32 = Int32(bytesPerRow)
|
||||
|
@ -178,7 +178,7 @@ static const int encoderPacketSizeInBytes = TGBridgeAudioEncoderSampleRate / 100
|
||||
if (_assetReader.status == AVAssetReaderStatusCompleted)
|
||||
{
|
||||
NSLog(@"finished");
|
||||
if (_oggWriter != nil && [_oggWriter writeFrame:NULL frameByteCount:0])
|
||||
if (_oggWriter != nil)
|
||||
{
|
||||
dataItemResult = _tempFileItem;
|
||||
durationResult = [_oggWriter encodedDuration];
|
||||
|
@ -271,7 +271,7 @@ final class CachedAnimatedStickerRepresentation: CachedMediaResourceRepresentati
|
||||
let height: Int32
|
||||
|
||||
var uniqueId: String {
|
||||
return "animated-sticker-\(self.width)x\(self.height)-v7"
|
||||
return "animated-sticker-\(self.width)x\(self.height)-v8"
|
||||
}
|
||||
|
||||
init(width: Int32, height: Int32) {
|
||||
|
@ -14,6 +14,92 @@ private let nameFont = Font.medium(14.0)
|
||||
private let inlineBotPrefixFont = Font.regular(14.0)
|
||||
private let inlineBotNameFont = nameFont
|
||||
|
||||
private class ChatMessageHeartbeatHaptic {
|
||||
private var hapticFeedback = HapticFeedback()
|
||||
var timer: SwiftSignalKit.Timer?
|
||||
var time: Double = 0
|
||||
var enabled = false {
|
||||
didSet {
|
||||
if !self.enabled {
|
||||
self.reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var active: Bool {
|
||||
return self.timer != nil
|
||||
}
|
||||
|
||||
private func reset() {
|
||||
if let timer = self.timer {
|
||||
self.time = 0.0
|
||||
timer.invalidate()
|
||||
self.timer = nil
|
||||
}
|
||||
}
|
||||
|
||||
private func beat(time: Double) {
|
||||
let epsilon = 0.1
|
||||
if fabs(0.0 - time) < epsilon || fabs(1.0 - time) < epsilon || fabs(2.0 - time) < epsilon {
|
||||
self.hapticFeedback.impact(.medium)
|
||||
} else if fabs(0.2 - time) < epsilon || fabs(1.2 - time) < epsilon || fabs(2.2 - time) < epsilon {
|
||||
self.hapticFeedback.impact(.light)
|
||||
}
|
||||
}
|
||||
|
||||
func start(time: Double) {
|
||||
self.hapticFeedback.prepareImpact()
|
||||
|
||||
if time > 2.0 {
|
||||
return
|
||||
}
|
||||
|
||||
var startTime: Double = 0.0
|
||||
var delay: Double = 0.0
|
||||
|
||||
if time > 0.0 {
|
||||
if time <= 1.0 {
|
||||
startTime = 1.0
|
||||
} else if time <= 2.0 {
|
||||
startTime = 2.0
|
||||
}
|
||||
}
|
||||
|
||||
delay = max(0.0, startTime - time)
|
||||
|
||||
let block = { [weak self] in
|
||||
guard let strongSelf = self, strongSelf.enabled else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.time = startTime
|
||||
strongSelf.beat(time: startTime)
|
||||
strongSelf.timer = SwiftSignalKit.Timer(timeout: 0.2, repeat: true, completion: { [weak self] in
|
||||
guard let strongSelf = self, strongSelf.enabled else {
|
||||
return
|
||||
}
|
||||
strongSelf.time += 0.2
|
||||
strongSelf.beat(time: strongSelf.time)
|
||||
|
||||
if strongSelf.time > 2.2 {
|
||||
strongSelf.reset()
|
||||
strongSelf.time = 0.0
|
||||
strongSelf.timer?.invalidate()
|
||||
strongSelf.timer = nil
|
||||
}
|
||||
|
||||
}, queue: Queue.mainQueue())
|
||||
strongSelf.timer?.start()
|
||||
}
|
||||
|
||||
if delay > 0.0 {
|
||||
Queue.mainQueue().after(delay, block)
|
||||
} else {
|
||||
block()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
let imageNode: TransformImageNode
|
||||
private let animationNode: AnimatedStickerNode
|
||||
@ -40,7 +126,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
|
||||
private var highlightedState: Bool = false
|
||||
|
||||
private var hapticFeedback: HapticFeedback?
|
||||
private var heartbeatHaptic: ChatMessageHeartbeatHaptic?
|
||||
|
||||
private var currentSwipeToReplyTranslation: CGFloat = 0.0
|
||||
|
||||
@ -125,6 +211,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
didSet {
|
||||
if self.visibilityStatus != oldValue {
|
||||
self.updateVisibility()
|
||||
self.heartbeatHaptic?.enabled = self.visibilityStatus
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -684,33 +771,34 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
if self.telegramFile != nil {
|
||||
let _ = item.controllerInteraction.openMessage(item.message, .default)
|
||||
} else if let _ = self.emojiFile {
|
||||
var startTime: Signal<Double, NoError>
|
||||
if self.animationNode.playIfNeeded() {
|
||||
if self.item?.message.text == "❤️" {
|
||||
let hapticFeedback: HapticFeedback
|
||||
if let currentHapticFeedback = self.hapticFeedback {
|
||||
hapticFeedback = currentHapticFeedback
|
||||
startTime = .single(0.0)
|
||||
} else {
|
||||
startTime = self.animationNode.status
|
||||
|> map { $0.timestamp }
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue
|
||||
}
|
||||
|
||||
if self.item?.message.text == "❤️" {
|
||||
let _ = startTime.start(next: { [weak self] time in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let heartbeatHaptic: ChatMessageHeartbeatHaptic
|
||||
if let current = strongSelf.heartbeatHaptic {
|
||||
heartbeatHaptic = current
|
||||
} else {
|
||||
hapticFeedback = HapticFeedback()
|
||||
self.hapticFeedback = hapticFeedback
|
||||
heartbeatHaptic = ChatMessageHeartbeatHaptic()
|
||||
heartbeatHaptic.enabled = true
|
||||
strongSelf.heartbeatHaptic = heartbeatHaptic
|
||||
}
|
||||
hapticFeedback.prepareImpact()
|
||||
hapticFeedback.impact(.medium)
|
||||
Queue.mainQueue().after(0.2) {
|
||||
hapticFeedback.impact(.light)
|
||||
Queue.mainQueue().after(0.78) {
|
||||
hapticFeedback.impact(.medium)
|
||||
Queue.mainQueue().after(0.2) {
|
||||
hapticFeedback.impact(.light)
|
||||
Queue.mainQueue().after(0.78) {
|
||||
hapticFeedback.impact(.medium)
|
||||
Queue.mainQueue().after(0.2) {
|
||||
hapticFeedback.impact(.light)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !heartbeatHaptic.active {
|
||||
heartbeatHaptic.start(time: time)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -557,7 +557,7 @@ final class ManagedAudioRecorderContext {
|
||||
self.currentPeak = max(Int64(sample), self.currentPeak)
|
||||
self.currentPeakCount += 1
|
||||
if self.currentPeakCount == self.peakCompressionFactor {
|
||||
var compressedPeak = self.currentPeak//Int16(Float(self.currentPeak) / Float(self.peakCompressionFactor))
|
||||
var compressedPeak = self.currentPeak
|
||||
withUnsafeBytes(of: &compressedPeak, { buffer in
|
||||
self.compressedWaveformSamples.append(buffer.bindMemory(to: UInt8.self))
|
||||
})
|
||||
@ -592,57 +592,53 @@ final class ManagedAudioRecorderContext {
|
||||
}
|
||||
|
||||
func takeData() -> RecordedAudioData? {
|
||||
if self.oggWriter.writeFrame(nil, frameByteCount: 0) {
|
||||
var scaledSamplesMemory = malloc(100 * 2)!
|
||||
var scaledSamples: UnsafeMutablePointer<Int16> = scaledSamplesMemory.assumingMemoryBound(to: Int16.self)
|
||||
defer {
|
||||
free(scaledSamplesMemory)
|
||||
}
|
||||
memset(scaledSamples, 0, 100 * 2);
|
||||
var waveform: Data?
|
||||
|
||||
let count = self.compressedWaveformSamples.count / 2
|
||||
self.compressedWaveformSamples.withUnsafeMutableBytes { (samples: UnsafeMutablePointer<Int16>) -> Void in
|
||||
for i in 0 ..< count {
|
||||
let sample = samples[i]
|
||||
let index = i * 100 / count
|
||||
if (scaledSamples[index] < sample) {
|
||||
scaledSamples[index] = sample;
|
||||
}
|
||||
}
|
||||
|
||||
var peak: Int16 = 0
|
||||
var sumSamples: Int64 = 0
|
||||
for i in 0 ..< 100 {
|
||||
let sample = scaledSamples[i]
|
||||
if peak < sample {
|
||||
peak = sample
|
||||
}
|
||||
sumSamples += Int64(sample)
|
||||
}
|
||||
var calculatedPeak: UInt16 = 0
|
||||
calculatedPeak = UInt16((Double(sumSamples) * 1.8 / 100.0))
|
||||
|
||||
if calculatedPeak < 2500 {
|
||||
calculatedPeak = 2500
|
||||
}
|
||||
|
||||
for i in 0 ..< 100 {
|
||||
let sample: UInt16 = UInt16(Int64(scaledSamples[i]))
|
||||
let minPeak = min(Int64(sample), Int64(calculatedPeak))
|
||||
let resultPeak = minPeak * 31 / Int64(calculatedPeak)
|
||||
scaledSamples[i] = Int16(clamping: min(31, resultPeak))
|
||||
}
|
||||
|
||||
let resultWaveform = AudioWaveform(samples: Data(bytes: scaledSamplesMemory, count: 100 * 2), peak: 31)
|
||||
let bitstream = resultWaveform.makeBitstream()
|
||||
waveform = AudioWaveform(bitstream: bitstream, bitsPerSample: 5).makeBitstream()
|
||||
}
|
||||
|
||||
return RecordedAudioData(compressedData: self.dataItem.data(), duration: self.oggWriter.encodedDuration(), waveform: waveform)
|
||||
} else {
|
||||
return nil
|
||||
var scaledSamplesMemory = malloc(100 * 2)!
|
||||
var scaledSamples: UnsafeMutablePointer<Int16> = scaledSamplesMemory.assumingMemoryBound(to: Int16.self)
|
||||
defer {
|
||||
free(scaledSamplesMemory)
|
||||
}
|
||||
memset(scaledSamples, 0, 100 * 2);
|
||||
var waveform: Data?
|
||||
|
||||
let count = self.compressedWaveformSamples.count / 2
|
||||
self.compressedWaveformSamples.withUnsafeMutableBytes { (samples: UnsafeMutablePointer<Int16>) -> Void in
|
||||
for i in 0 ..< count {
|
||||
let sample = samples[i]
|
||||
let index = i * 100 / count
|
||||
if (scaledSamples[index] < sample) {
|
||||
scaledSamples[index] = sample;
|
||||
}
|
||||
}
|
||||
|
||||
var peak: Int16 = 0
|
||||
var sumSamples: Int64 = 0
|
||||
for i in 0 ..< 100 {
|
||||
let sample = scaledSamples[i]
|
||||
if peak < sample {
|
||||
peak = sample
|
||||
}
|
||||
sumSamples += Int64(sample)
|
||||
}
|
||||
var calculatedPeak: UInt16 = 0
|
||||
calculatedPeak = UInt16((Double(sumSamples) * 1.8 / 100.0))
|
||||
|
||||
if calculatedPeak < 2500 {
|
||||
calculatedPeak = 2500
|
||||
}
|
||||
|
||||
for i in 0 ..< 100 {
|
||||
let sample: UInt16 = UInt16(Int64(scaledSamples[i]))
|
||||
let minPeak = min(Int64(sample), Int64(calculatedPeak))
|
||||
let resultPeak = minPeak * 31 / Int64(calculatedPeak)
|
||||
scaledSamples[i] = Int16(clamping: min(31, resultPeak))
|
||||
}
|
||||
|
||||
let resultWaveform = AudioWaveform(samples: Data(bytes: scaledSamplesMemory, count: 100 * 2), peak: 31)
|
||||
let bitstream = resultWaveform.makeBitstream()
|
||||
waveform = AudioWaveform(bitstream: bitstream, bitsPerSample: 5).makeBitstream()
|
||||
}
|
||||
|
||||
return RecordedAudioData(compressedData: self.dataItem.data(), duration: self.oggWriter.encodedDuration(), waveform: waveform)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user