为什么在运行iOS 14的iPhone中听不到AVMIDIPlayer播放的声音?

问题描述

我有一个使用Swift UI开发的非常简单的iOS应用,该应用使用AVMIDIPlayer播放一系列MIDI事件。

我在本地测试了该事件序列,创建了一个.midi文件,并使用Garageband执行该文件输出按预期工作。

但是,当我的应用程序播放它时,我没有收到任何错误,但也没有声音。相关代码


import SwiftUI

let WELLCOME_MESSAGE = "hey there! Guess the sequence!"
let PLAYING_SEQUENCE = "Playing the Sequence..."
let MAJOR_THIRD = "Guessed Major Third"
let MInor_THIRD = "Guessed Minor Third"
let CORRECT_GUESS = "You guessed correctly! Hurray!"
let INCORRECT_GUESS = "You guessed wrongly! Looser!"

enum Note: UInt8,CaseIterable {
    case MajorThird = 4
    case MinorThird = 3
}

struct ContentView: View {
    @State var score: Int = 0
    @State var message: String = WELLCOME_MESSAGE
    @State var intervalPlayer: IntervalPlayer! = IntervalPlayer.init(root: UInt8.random(in: 60...71),interval: Note.allCases.randomElement()!.rawValue)
    
    fileprivate func processGuess(note: Note,resetAction: (String) -> Void) {
        var result: String = ""
        if self.intervalPlayer.interval == note.rawValue {
            self.score += 1
            result = CORRECT_GUESS
        } else {
            result = INCORRECT_GUESS
        }
        resetAction(result)
    }
    
    var body: some View {
        let resetAction: (String) -> Void = { message in
            self.message = message
            self.intervalPlayer.setInterval(root: UInt8.random(in: 60...71),interval: Note.allCases.randomElement()!.rawValue)
        }
        vstack {
            Text("\(self.message)")
                .padding()
            Button("Play Sequence",action: {
                self.message = PLAYING_SEQUENCE
                self.intervalPlayer.playInterval()
            })
            .padding(.bottom)
            HStack {
                Button("Guess Major Third",action: {
                    self.message = MAJOR_THIRD
                    dispatchQueue.main.asyncAfter(deadline: .Now() + .seconds(5)) {
                        processGuess(note: Note.MajorThird,resetAction: resetAction)
                    }
                })
                .padding(.trailing)
                Button("Guess Minor Third",action: {
                    self.message = MInor_THIRD;
                    dispatchQueue.main.asyncAfter(deadline: .Now() + .seconds(5)) {
                        processGuess(note: Note.MinorThird,resetAction: resetAction)
                    }
                })
                .padding(.leading)
            }
            Text("Your score is \(self.score)")
                .padding(.top)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
import AVFoundation
import Foundation

let INTERVAL_MIDI_HEADER: [UInt8] = [
    0x4D,0x54,0x68,0x64,// MIDI header: MThd
    0x00,0x00,0x06,// MIDI header length: 6 bytes
    0x00,// Single channel
    0x00,0x01,// Number of channels
    0x00,// Number of ticks per beat: 1 tick per beat
    0x4D,0x72,0x6b,// Track header: MThd
]

let INTERVAL_MIDI_TRACK_MetaDATA: [UInt8] = [
    0x00,0x3A,// Track length: 4 bytes * 8 events + 4 bytes for end of header + 22 for the headers = 58
    0x00,0xFF,0x58,0x04,// Specify time signature,and clarify that the next four bytes will contain that information
    0x04,0x18,0x08,// Time signature is 4/4,and 0x18 MIDI clocks in a metronome clock
    0x00,0x51,0x03,// Specify the tempo of the track.
    0x08,0x7a,0x23,// 1,000,000 microseconds per quarter note. Because it is in 4/4,this means 60 bpm.
    0x00,0xc0,0x4f,// Set MIDI instrument to 79 (Flute)
    0x00,0xb0,0x07,0x20,// Main volume
]

let END_OF_TRACK_BYTES: [UInt8] = [0x00,0xff,0x2f,0x00]

struct IntervalPlayer {
    var midiPlayer: AVMIDIPlayer?
    var root: UInt8!
    var interval: UInt8!
    
    init(root: UInt8,interval: UInt8) {
        self.setInterval(root: root,interval: interval)
    }
    
    mutating func setInterval(root: UInt8,interval: UInt8) {
        self.root = root
        self.interval = interval
        let intervalNote = root + interval
        let sequence: [UInt8] = INTERVAL_MIDI_HEADER + INTERVAL_MIDI_TRACK_MetaDATA + [
            0x00,0x90,root,0x40,// Play the root at beat 1.
            0x01,0x80,// Stop playing the root at beat 2.
            0x00,intervalNote,// Play the interval at beat 2.
            0x01,// Stop playing the interval at beat 3.
            0x01,// Play the interval at beat 4.
            0x01,// Stop playing the interval at beat 5.
            0x00,// Play the root at beat 5.
            0x01,// Stop playing the root at beat 6.
        ] + END_OF_TRACK_BYTES
        let data = Data.init(sequence)
        
        guard let bankURL = Bundle.main.url(forResource: "FluidR3_GM",withExtension: "sf2") else {
            fatalError("soundbank file not found.")
        }
        do {
            self.midiPlayer = try AVMIDIPlayer.init(data: data,soundBankURL: bankURL)
            print("created midi player with sound bank url \(bankURL)")
            self.midiPlayer!.preparetoPlay()
            print("PREPARES TO PLAY")
        } catch let error as NSError {
            print("Error \(error.localizedDescription)")
        }
    }
    func playInterval() {
        if !self.midiPlayer!.isPlaying {
            self.midiPlayer!.currentPosition = 0
            self.midiPlayer!.play({
                print("FINISHED")
            })
            print("PLAYS?")
        }
    }
}

当我用Google搜索类似问题时,似乎每个人都认为问题是midiPlayer寿命不足。但是,这里似乎并非如此。当我单击“播放序列...”按钮时,在终端中,我看到以下消息:

PLAYS?
FINISHED

符合预期。 FINISHED会在PLAYS之后大约3秒钟出现,这也是音频持续的时间。但是,再次没有声音播放。

感谢您的帮助!

谢谢。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)