swift - 在 Swift 中产生不同频率的声音

标签 swift audio frequency

我想做一个像this这样的应用程序。这个应用程序是驱蚊应用程序,会产生某种频率的声音。我不希望它仅限于一种声音。我想为不同的目的生成和播放不同频率的声音。我怎样才能在 swift IOS 中做到这一点?如何在 swift ios 中创建特定频率的声音?

最佳答案

swift 4.2: 在您的项目中创建此类。

import Foundation
import AudioUnit
import AVFoundation

final class ToneOutputUnit: NSObject {
    
    var auAudioUnit: AUAudioUnit! = nil     // placeholder for RemoteIO Audio Unit
    
    var avActive     = false             // AVAudioSession active flag
    var audioRunning = false             // RemoteIO Audio Unit running flag
    
    var sampleRate : Double = 44100.0    // typical audio sample rate
    
    var f0  =    880.0              // default frequency of tone:   'A' above Concert A
    var v0  =  16383.0              // default volume of tone:      half full scale
    
    var toneCount : Int32 = 0       // number of samples of tone to play.  0 for silence
    
    private var phY =     0.0       // save phase of sine wave to prevent clicking
    private var interrupted = false     // for restart from audio interruption notification
    
    
    
    func setFrequency(freq : Double) {  // audio frequencies below 500 Hz may be
        f0 = freq                       //   hard to hear from a tiny iPhone speaker.
    }
    
    func setToneVolume(vol : Double) {  // 0.0 to 1.0
        v0 = vol * 32766.0
    }
    
    func setToneTime(t : Double) {
        toneCount = Int32(t * sampleRate);
    }
    
    func enableSpeaker() {
        
        if audioRunning {
            
            print("returned")
            return
            
        }           // return if RemoteIO is already running
        
        
        
        do {        // not running, so start hardware
            
            let audioComponentDescription = AudioComponentDescription(
                componentType: kAudioUnitType_Output,
                componentSubType: kAudioUnitSubType_SystemOutput, // For output to the local sound system
                componentManufacturer: kAudioUnitManufacturer_Apple,
                componentFlags: 0,
                componentFlagsMask: 0 )
            
            if (auAudioUnit == nil) {
                
               auAudioUnit = try AUAudioUnit(componentDescription: audioComponentDescription)
                
                let bus0 = auAudioUnit.inputBusses[0]
                
                let audioFormat = AVAudioFormat(
                    commonFormat: AVAudioCommonFormat.pcmFormatInt16,   // short int samples
                    sampleRate: Double(sampleRate),
                    channels:AVAudioChannelCount(2),
                    interleaved: true )                                 // interleaved stereo
                
                try bus0.setFormat(audioFormat ?? AVAudioFormat())  //      for speaker bus
                
                auAudioUnit.outputProvider = { (    //  AURenderPullInputBlock?
                    actionFlags,
                    timestamp,
                    frameCount,
                    inputBusNumber,
                    inputDataList ) -> AUAudioUnitStatus in
                    
                    self.fillSpeakerBuffer(inputDataList: inputDataList, frameCount: frameCount)
                    return(0)
                }
            }
                        
            auAudioUnit.isOutputEnabled = true
            toneCount = 0
            
            try auAudioUnit.allocateRenderResources()  //  v2 AudioUnitInitialize()
            try auAudioUnit.startHardware()            //  v2 AudioOutputUnitStart()
            audioRunning = true
            
        } catch /* let error as NSError */ {
            print("error 2 \(error)")
        }
        
        
    }
    
    // helper functions
    
    private func fillSpeakerBuffer(     // process RemoteIO Buffer for output
        inputDataList : UnsafeMutablePointer<AudioBufferList>, frameCount : UInt32 ) {
        let inputDataPtr = UnsafeMutableAudioBufferListPointer(inputDataList)
        let nBuffers = inputDataPtr.count
        if (nBuffers > 0) {
            
            let mBuffers : AudioBuffer = inputDataPtr[0]
            let count = Int(frameCount)
            
            // Speaker Output == play tone at frequency f0
            if (   self.v0 > 0)
                && (self.toneCount > 0 )
            {
                // audioStalled = false
                
                var v  = self.v0 ; if v > 32767 { v = 32767 }
                let sz = Int(mBuffers.mDataByteSize)
                
                var a  = self.phY        // capture from object for use inside block
                let d  = 2.0 * Double.pi * self.f0 / self.sampleRate     // phase delta
                
                let bufferPointer = UnsafeMutableRawPointer(mBuffers.mData)
                if var bptr = bufferPointer {
                    for i in 0..<(count) {
                        let u  = sin(a)             // create a sinewave
                        a += d ; if (a > 2.0 * Double.pi) { a -= 2.0 * Double.pi }
                        let x = Int16(v * u + 0.5)      // scale & round
                        
                        if (i < (sz / 2)) {
                            bptr.assumingMemoryBound(to: Int16.self).pointee = x
                            bptr += 2   // increment by 2 bytes for next Int16 item
                            bptr.assumingMemoryBound(to: Int16.self).pointee = x
                            bptr += 2   // stereo, so fill both Left & Right channels
                        }
                    }
                }
                
                self.phY        =   a                   // save sinewave phase
                self.toneCount  -=  Int32(frameCount)   // decrement time remaining
            } else {
                // audioStalled = true
                memset(mBuffers.mData, 0, Int(mBuffers.mDataByteSize))  // silence
            }
        }
    }
    
    
    
    func stop() {
        if (audioRunning) {
            auAudioUnit.stopHardware()
            audioRunning = false
        }
    }
}

并在 View Controller 中通过 viewDidLoad() 方法创建此类的对象。

let myUnit = ToneOutputUnit()

要创建特定频率(此处为 10,000)的声音,请使用以下代码

    myUnit.setFrequency(freq: 10000)
    myUnit.setToneVolume(vol: currentVolume)
    myUnit.enableSpeaker()
    myUnit.setToneTime(t: 20000)

并停止声音

myUnit.stop()

关于swift - 在 Swift 中产生不同频率的声音,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55572894/

相关文章:

haskell - 将 wav 音频格式 ByteString 转换为 Floats

python : how to change audio volume?

ios - DFT 结果使用来自 Swift 的 vDSP 来自实值输入(Surge 实现)

python - 如何在 python 中创建一个程序来打印字符串中单词的出现次数

swift - 如何解决此构建问题 - 无法分配给属性 : 'date' is a get only property

ios - 搜索 CoreData 以匹配 NSDate - Swift

swift - 带有 UICollectionView 的 UIToolBar

python - 使用Python生成滑动音

swift - 如何从 scaleAspectFit 模式的 UIImageView 的 UIImage 获取快照?

java - FFT 中频率检测的问题