All Projects → Dywane → Mcchathud

Dywane / Mcchathud

MatchaSKD中录音波形图实现,并增加其他多种样式

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Mcchathud

Wavelineview
A memory-friendly recording wave animation一款性能内存友好的录音波浪动画
Stars: ✭ 597 (+862.9%)
Mutual labels:  recorder
Swiftnotice
GUI library for displaying various popups (HUD), written in pure Swift.
Stars: ✭ 825 (+1230.65%)
Mutual labels:  hud
Cocoaasyncsocket demo
基于AsyncSocket搭建即时通讯体系 . 包含TCP连接 , 消息发送 , 消息接收 , 心跳处理 ,断网重连 , 消息超时 , 消息分发 , 数据库结构设计 , 消息丢失等 . 以及UI设计, 文本表情消息/语音消息/图片消息/视频消息/文件消息/撤回消息/提示语消息的实现思路讲解
Stars: ✭ 981 (+1482.26%)
Mutual labels:  ios-demo
Trinity
android video record editor muxer sdk
Stars: ✭ 609 (+882.26%)
Mutual labels:  recorder
Ksystreamer android
金山云Android采集推流SDK(Livestream SDK),支持内置/自定义美颜(Beauty Filter)、美声(Beauty Voice)、软硬编(Software/Hardware Encoder) 、网络自适应(Network Auto Adapt)、混音(Voice Mixer)、混响(Reverb)、画中画(PIP)、连麦(RTC)、动态贴纸(Sticker)、大眼瘦脸(Bigger Eyes and Smaller Faces)
Stars: ✭ 702 (+1032.26%)
Mutual labels:  recorder
Spy Spotify
🎤 Records Spotify to mp3 without ads and adds media tags to the files 🎵
Stars: ✭ 929 (+1398.39%)
Mutual labels:  recorder
Wsprogresshud
This is a beauful hud view for iPhone & iPad
Stars: ✭ 588 (+848.39%)
Mutual labels:  hud
React Mp3 Recorder
Microphone recorder for React that captures mp3 audio 🎵
Stars: ✭ 59 (-4.84%)
Mutual labels:  recorder
Gsyrecordwave
MP3音频录制,支持类似IOS原生的单边或者双边波形显示,低版本音频权限兼容,本地或者在线音频播放的波形显示,录制波形和播放波形会根据声音频率变色的功能,边播边缓存功能,简书入口http://www.jianshu.com/p/2448e2903b07
Stars: ✭ 810 (+1206.45%)
Mutual labels:  recorder
Avsqldebugger
A Simple Core Data Debugger that will look inside your apps DB
Stars: ✭ 30 (-51.61%)
Mutual labels:  ios-demo
Iosproject
iOS project of collected some demos for iOS App, use Objective-C
Stars: ✭ 5,357 (+8540.32%)
Mutual labels:  ios-demo
Wmzdialog
功能最多样式最多的弹窗,支持普通/微信底部/日期/地区/日历/选择/编辑/分享/菜单/自定义弹窗等,支持多种动画,链式编程调用(Pop-up windows with the most functions and styles, support normal/WeChat bottom/date/region/calendar/select/edit/share/menu/custom pop-up windows, etc., support multiple animations, chain programming calls)
Stars: ✭ 673 (+985.48%)
Mutual labels:  hud
Bull Record Everything
Bull-Record-Everything is a convenient tool which can be used to record everything, eg : desktop, camera, window , and it's also has capacities to mix speaker or microphone to a media file.
Stars: ✭ 25 (-59.68%)
Mutual labels:  recorder
Screenity
The most powerful screen recorder & annotation tool for Chrome 🎥
Stars: ✭ 6,229 (+9946.77%)
Mutual labels:  recorder
Kbnhud
My TF2 HUD and one of many hobby projects. Readme has the info and links you need.
Stars: ✭ 36 (-41.94%)
Mutual labels:  hud
Green Recorder
A simple screen recorder for Linux desktop. Supports Wayland & Xorg
Stars: ✭ 594 (+858.06%)
Mutual labels:  recorder
Avirecorder
A recording tool for source-based games.
Stars: ✭ 22 (-64.52%)
Mutual labels:  recorder
Rtp Streamer
rtp record and rtp streamer
Stars: ✭ 60 (-3.23%)
Mutual labels:  recorder
Jhud
A full screen of the HUD when loading the data (Objective-C).
Stars: ✭ 1,003 (+1517.74%)
Mutual labels:  hud
Chipkizi
a recording app for up and coming artists
Stars: ✭ 26 (-58.06%)
Mutual labels:  recorder

MCChatHUD

MatchaSKD中录音波形图实现Demo,并增加新的样式。

文章地址

效果图

条状波形图 线装波形图

实现方式

配置AvAudioSession

绘制波形图前首先需要配置好AVAudioSession,同时需要建立一个数组去保存音量数据。

相关属性

  • recorderSetting用于设定录音音质等相关数据。
  • timer以及updateFequency用于定时更新波形图。
  • soundMetersoundMeterCount用于保存音量表数组。
  • recordTime用于记录录音时间,可以用于判断录音时间是否达到要求等进一波需求。
	 /// 录音器
    private var recorder: AVAudioRecorder!
    /// 录音器设置
    private let recorderSetting = [AVSampleRateKey : NSNumber(value: Float(44100.0)),//声音采样率
                                     AVFormatIDKey : NSNumber(value: Int32(kAudioFormatMPEG4AAC)),//编码格式
                             AVNumberOfChannelsKey : NSNumber(value: 1),//采集音轨
                          AVEncoderAudioQualityKey : NSNumber(value: Int32(AVAudioQuality.medium.rawValue))]//声音质量
    /// 录音计时器
    private var timer: Timer?
    /// 波形更新间隔
    private let updateFequency = 0.05
    /// 声音数据数组
    private var soundMeters: [Float]!
    /// 声音数据数组容量
    private let soundMeterCount = 10
    /// 录音时间
    private var recordTime = 0.00

AvAudioSession相关配置

  • configAVAudioSession用于配置AVAudioSession,其中AVAudioSessionCategoryRecord是代表仅仅利用这个session进行录音操作,而需要播放操作的话是可以设置成AVAudioSessionCategoryPlayAndRecordAVAudioSessionCategoryPlayBlack,两者区别一个是可以录音和播放,另一个是可以在后台播放(即静音后仍然可以播放语音)。
  • configRecord是用于配置整个AVAudioRecoder,包括权限获取、代理源设置、是否记录音量表等。
  • directoryURL是用于配置文件保存地址。
    private func configAVAudioSession() {
        let session = AVAudioSession.sharedInstance()
        do { try session.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .defaultToSpeaker) }
        catch { print("session config failed") }
    }
    
    
    private func configRecord() {
        AVAudioSession.sharedInstance().requestRecordPermission { (allowed) in
            if !allowed {
                return
            }
        }
        let session = AVAudioSession.sharedInstance()
        do { try session.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .defaultToSpeaker) }
        catch { print("session config failed") }
        do {
            self.recorder = try AVAudioRecorder(url: self.directoryURL()!, settings: self.recorderSetting)
            self.recorder.delegate = self
            self.recorder.prepareToRecord()
            self.recorder.isMeteringEnabled = true
        } catch {
            print(error.localizedDescription)
        }
        do { try AVAudioSession.sharedInstance().setActive(true) }
        catch { print("session active failed") }
    }
    
    
    private func directoryURL() -> URL? {
        // do something ...
        return soundFileURL
    }

记录音频数据

在开始录音后,利用我们刚刚配置的定时器不断获取averagePower,并保存到数组之中。

  • updateMeters被定时器调用,不断将recorder中记录的音量数据保存到soundMeter数组中。
  • addSoundMeter用于完成添加数据的工作。
    private func updateMeters() {
        recorder.updateMeters()
        recordTime += updateFequency
        addSoundMeter(item: recorder.averagePower(forChannel: 0))
    }
    
    
    private func addSoundMeter(item: Float) {
        if soundMeters.count < soundMeterCount {
            soundMeters.append(item)
        } else {
            for (index, _) in soundMeters.enumerated() {
                if index < soundMeterCount - 1 {
                    soundMeters[index] = soundMeters[index + 1]
                }
            }
            // 插入新数据
            soundMeters[soundMeterCount - 1] = item
            NotificationCenter.default.post(name: NSNotification.Name.init("updateMeters"), object: soundMeters)
        }
    }

开始绘制波形图

现在我们已经获取了我们需要的所有数据,可以开始绘制波形图了。这时候让我们转到MCVolumeView.swift文件中,在上一个步骤中,我们发送了一条叫做updateMeters的通知,目的就是为了通知MCVolumeView进行波形图的更新。

	override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor.clear
        contentMode = .redraw   //内容模式为重绘,因为需要多次重复绘制音量表
        NotificationCenter.default.addObserver(self, selector: #selector(updateView(notice:)), name: NSNotification.Name.init("updateMeters"), object: nil)
    }
    
    @objc private func updateView(notice: Notification) {
        soundMeters = notice.object as! [Float]
        setNeedsDisplay()
    }

setNeedsDisplay被调用之后,就会调用drawRect方法,在这里我们可以进行绘制波形图的操作。

  • noVoicemaxVolume是用于确保声音的显示范围
  • 波形图的绘制使用CGContext进行绘制,当然也可以使用UIBezierPath进行绘制。
    override func draw(_ rect: CGRect) {
        if soundMeters != nil && soundMeters.count > 0 {
            let context = UIGraphicsGetCurrentContext()
            context?.setLineCap(.round)
            context?.setLineJoin(.round)
            context?.setStrokeColor(UIColor.white.cgColor)
            
            let noVoice = -46.0     // 该值代表低于-46.0的声音都认为无声音
            let maxVolume = 55.0    // 该值代表最高声音为55.0
            
			  // draw the volume...            
			  
            context?.strokePath()
        }
    }

柱状波形图的绘制

  • 根据maxVolumenoVoice计算出每一条柱状的高度,并移动context所在的点进行绘制
  • 另外需要注意的是CGContext中坐标点时反转的,所以在进行计算时需要将坐标轴进行反转来计算。
    case .bar:
        context?.setLineWidth(3)
        for (index,item) in soundMeters.enumerated() {
            let barHeight = maxVolume - (Double(item) - noVoice)    //通过当前声音表计算应该显示的声音表高度
            context?.move(to: CGPoint(x: index * 6 + 3, y: 40))
            context?.addLine(to: CGPoint(x: index * 6 + 3, y: Int(barHeight)))
        }

线状波形图的绘制

  • 线状与条状一样使用同样的方法计算“高度”,但是在绘制条状波形图时,是先画线,再移动,而绘制条状波形图时是先移动再画线。
	case .line:
        context?.setLineWidth(1.5)
        for (index, item) in soundMeters.enumerated() {
            let position = maxVolume - (Double(item) - noVoice)     //计算对应线段高度
            context?.addLine(to: CGPoint(x: Double(index * 6 + 3), y: position))
            context?.move(to: CGPoint(x: Double(index * 6 + 3), y: position))
        }

进一步完善我们的波形图

在很多时候,录音不单止是需要显示波形图,还需要我们展示目前录音的时间和进度,所以我们可以在波形图上添加录音的进度条,所以我们转向MCProgressView.swift文件进行操作。

  • 使用UIBezierPath配合CAShapeLayer进行绘制。
  • maskPath是作为整个进度路径的蒙版,因为我们的录音HUD不是规则的方形,所以需要使用蒙版进度路径进行裁剪。
  • progressPath为进度路径,进度的绘制方法为从左到右依次绘制。
  • animation是进度路径的绘制动画。
    private func configAnimate() {
        let maskPath = UIBezierPath(roundedRect: CGRect.init(x: 0, y: 0, width:             frame.width, height: frame.height), cornerRadius: HUDCornerRadius)
        let maskLayer = CAShapeLayer()
        maskLayer.backgroundColor = UIColor.clear.cgColor
        maskLayer.path = maskPath.cgPath
        maskLayer.frame = bounds
        
        // 进度路径
        /*
         路径的中心为HUD的中心,宽度为HUD的高度,从左往右绘制
         */
        let progressPath = CGMutablePath()
        progressPath.move(to: CGPoint(x: 0, y: frame.height / 2))
        progressPath.addLine(to: CGPoint(x: frame.width, y: frame.height / 2))
        
        progressLayer = CAShapeLayer()
        progressLayer.frame = bounds
        progressLayer.fillColor = UIColor.clear.cgColor //图层背景颜色
        progressLayer.strokeColor = UIColor(red: 0.29, green: 0.29, blue: 0.29, alpha: 0.90).cgColor   //图层绘制颜色
        progressLayer.lineCap = kCALineCapButt
        progressLayer.lineWidth = HUDHeight
        progressLayer.path = progressPath
        progressLayer.mask = maskLayer 
        
        animation = CABasicAnimation(keyPath: "strokeEnd")
        animation.duration = 60 //最大录音时长
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)    //匀速前进
        animation.fillMode = kCAFillModeForwards
        animation.fromValue = 0.0
        animation.toValue = 1.0
        animation.autoreverses = false
        animation.repeatCount = 1
    }

需求环境

  • iOS 10.0
  • Swift 4.0

Contribution

You are welcome to contribute to the project by forking the repo, modifying the code and opening issues or pull requests.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].