如何让iOS设备以编程方式播放音乐?

时间:2022-08-26 00:06:39

I'm trying to make my iphone play a tune without using prerecorded files. What are my options here? AVAudioEngine, AudioKit? I've looked at them, but the learning curve is relatively steep for something I'm hoping is easy. They also seem like tools for creating sound effect given a PCM buffer window.

我试图让我的iphone播放曲调,而不使用预先录制的文件。我有什么选择? AVAudioEngine,AudioKit?我看过它们,但学习曲线相对陡峭,我希望这很容易。在PCM缓冲窗口中,它们看起来也像是创建声音效果的工具。

I'd like to be able to do something like

我希望能够做类似的事情

pitchCreator.play(["C4", "E4", "G4"], durations: [1, 1, 1])

Preferrably sounding like an instrument or at least not like a pure sine wave.

最好听起来像仪器或至少不像纯正弦波。

1 个解决方案

#1


0  

EDIT: The below code has been replaced by AudioKit

编辑:以下代码已被AudioKit取代

To anyone wondering this; I did make it work (kind of) using code similar to the one below.

对任何想知道这一点的人;我确实使用类似下面的代码使其工作(种类)。

class PitchCreator {
  var engine: AVAudioEngine
  var player: AVAudioPlayerNode
  var mixer: AVAudioMixerNode
  var buffer: AVAudioPCMBuffer

  init() {
    engine = AVAudioEngine()
    player = AVAudioPlayerNode()
    mixer = engine.mainMixerNode;
    buffer = AVAudioPCMBuffer(PCMFormat: player.outputFormatForBus(0), frameCapacity: 100)
    buffer.frameLength = 4096
    engine.attachNode(player)
    engine.connect(player, to: mixer, format: player.outputFormatForBus(0))
  }

  func play(frequency: Float) {
    let signal = self.createSignal(frequency, amplitudes: [1.0, 0.5, 0.3, 0.1], bufferSize: Int(buffer.frameLength), sampleRate: Float(mixer.outputFormatForBus(0).sampleRate))
    for i in 0 ..< signal.count {
      buffer.floatChannelData.memory[i] = 0.5 * signal[i]
    }
    do {
      try engine.start()
      player.play()
      player.scheduleBuffer(buffer, atTime: nil, options: .Loops, completionHandler: nil)
    } catch {}
  }

  func stop() {
    engine.stop()
    player.stop()
  }

  func createSignal(frequency: Float, amplitudes: [Float], bufferSize: Int, sampleRate: Float) -> [Float] {
    let π = Float(M_PI)
    let T = sampleRate / frequency
    var x = [Float](count: bufferSize, repeatedValue: 0.0)
    for k in 0 ..< x.count {
      for h in 0 ..< amplitudes.count {
        x[k] += amplitudes[h] * sin(2.0 * π * Float(h + 1) * Float(k) / T)
      }
    }
    return x
  }
}

But it doesn't sound good enough so I've gone with sampling the notes I need and just use AVAudioPlayer instead to play them.

但它听起来不够好所以我已经采用了我需要的音符样本,而只是使用AVAudioPlayer来播放它们。

#1


0  

EDIT: The below code has been replaced by AudioKit

编辑:以下代码已被AudioKit取代

To anyone wondering this; I did make it work (kind of) using code similar to the one below.

对任何想知道这一点的人;我确实使用类似下面的代码使其工作(种类)。

class PitchCreator {
  var engine: AVAudioEngine
  var player: AVAudioPlayerNode
  var mixer: AVAudioMixerNode
  var buffer: AVAudioPCMBuffer

  init() {
    engine = AVAudioEngine()
    player = AVAudioPlayerNode()
    mixer = engine.mainMixerNode;
    buffer = AVAudioPCMBuffer(PCMFormat: player.outputFormatForBus(0), frameCapacity: 100)
    buffer.frameLength = 4096
    engine.attachNode(player)
    engine.connect(player, to: mixer, format: player.outputFormatForBus(0))
  }

  func play(frequency: Float) {
    let signal = self.createSignal(frequency, amplitudes: [1.0, 0.5, 0.3, 0.1], bufferSize: Int(buffer.frameLength), sampleRate: Float(mixer.outputFormatForBus(0).sampleRate))
    for i in 0 ..< signal.count {
      buffer.floatChannelData.memory[i] = 0.5 * signal[i]
    }
    do {
      try engine.start()
      player.play()
      player.scheduleBuffer(buffer, atTime: nil, options: .Loops, completionHandler: nil)
    } catch {}
  }

  func stop() {
    engine.stop()
    player.stop()
  }

  func createSignal(frequency: Float, amplitudes: [Float], bufferSize: Int, sampleRate: Float) -> [Float] {
    let π = Float(M_PI)
    let T = sampleRate / frequency
    var x = [Float](count: bufferSize, repeatedValue: 0.0)
    for k in 0 ..< x.count {
      for h in 0 ..< amplitudes.count {
        x[k] += amplitudes[h] * sin(2.0 * π * Float(h + 1) * Float(k) / T)
      }
    }
    return x
  }
}

But it doesn't sound good enough so I've gone with sampling the notes I need and just use AVAudioPlayer instead to play them.

但它听起来不够好所以我已经采用了我需要的音符样本,而只是使用AVAudioPlayer来播放它们。