You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Swift在iOS设备生成20kHz特定频率超声波?

嘿,刚好我对iOS音频这块熟,给你一套用Swift生成20kHz超声波的现代方案——那些旧的gist早就跟不上iOS的API更新了,咱用当前iOS推荐的AVAudioEngine来实现,靠谱得多!

用Swift在iOS生成20kHz超声波的实现方案

核心思路

iOS现在处理自定义音频生成,首选AVFoundation框架里的AVAudioEngine,它比旧API更稳定,适配所有主流iOS版本。我们会通过自定义音频源节点实时生成20kHz的正弦波,再通过设备扬声器输出。

步骤1:配置权限与导入框架

首先得搞定权限和基础配置:

  1. 在Info.plist里添加音频权限描述:新增NSAudioUsageDescription键,值填类似“需要生成超声波用于设备测试”的说明(iOS 10+强制要求)。
  2. 在代码文件顶部导入框架:
import AVFoundation

步骤2:实现超声波生成核心代码

下面是完整的可运行代码,我加了详细注释帮你理解:

class UltrasonicGenerator {
    private let engine = AVAudioEngine()
    private let targetFrequency: Double = 20000 // 目标20kHz频率
    private let sampleRate: Double = 48000 // 选48kHz采样率,更适配高频信号输出
    
    func startGenerating() throws {
        // 1. 配置音频会话为播放模式
        let audioSession = AVAudioSession.sharedInstance()
        try audioSession.setCategory(.playback, mode: .default)
        try audioSession.setActive(true)
        
        // 2. 创建自定义音频源节点,实时生成正弦波
        let sourceNode = AVAudioSourceNode { [weak self] _, _, frameCount, audioBufferList -> OSStatus in
            guard let self = self else { return noErr }
            
            let bufferList = UnsafeMutableAudioBufferListPointer(audioBufferList)
            let totalSamples = Int(frameCount)
            
            // 遍历每个音频缓冲区,填充采样数据
            for buffer in bufferList {
                guard let channelData = buffer.mData else { continue }
                let dataPointer = channelData.assumingMemoryBound(to: Float.self)
                
                // 生成20kHz正弦波的每个采样点
                for sampleIndex in 0..<totalSamples {
                    let time = Double(sampleIndex) / self.sampleRate
                    let sineValue = sin(2 * .pi * self.targetFrequency * time)
                    dataPointer[sampleIndex] = Float(sineValue) * 0.5 // 降低音量避免高频失真
                }
            }
            return noErr
        }
        
        // 3. 将源节点添加到引擎并连接到主混音器
        engine.attach(sourceNode)
        let outputFormat = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: 1)
        engine.connect(sourceNode, to: engine.mainMixerNode, format: outputFormat)
        
        // 4. 启动音频引擎
        try engine.start()
    }
    
    func stopGenerating() {
        engine.stop()
        do {
            try AVAudioSession.sharedInstance().setActive(false)
        } catch {
            print("停止音频会话失败: \(error.localizedDescription)")
        }
    }
}

步骤3:在界面中调用生成器

在你的ViewController里可以这样快速测试:

class ViewController: UIViewController {
    let ultrasonicGenerator = UltrasonicGenerator()
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        // 先请求音频权限
        AVAudioSession.sharedInstance().requestRecordPermission { [weak self] granted in
            DispatchQueue.main.async {
                if granted {
                    do {
                        try self?.ultrasonicGenerator.startGenerating()
                        print("已开始输出20kHz超声波")
                    } catch {
                        print("启动失败: \(error.localizedDescription)")
                    }
                } else {
                    print("需要授予音频权限才能生成超声波")
                }
            }
        }
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        ultrasonicGenerator.stopGenerating()
    }
}

关键注意事项

  • 硬件限制:不是所有iOS设备都能输出20kHz!比如部分旧款iPhone/iPad的扬声器频率上限在18kHz左右,一定要在目标设备上实际测试。
  • 无声音提示:20kHz属于超声波,人类耳朵基本听不到,播放时你不会有听觉反馈,可以用频谱分析仪验证输出。
  • 后台播放:如果需要在后台持续生成,要在Info.plist里添加UIBackgroundModes并勾选audio选项。
  • 音量调整:代码里把音量降到了0.5倍,是为了避免高频信号导致的音频失真,你可以根据需求微调。

内容的提问来源于stack exchange,提问作者Jonas0000

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:02:17