Swift AVMIDIPlayer play MIDI with sound bank doesn't play - swift

I'm trying to play a MIDI file with a sound font but it doesn't play. On simulator it always do a standard font but it's correct in iOS device it gives me an error
the error
2023-02-19 06:27:07.545221+0100 BlindMusic[596:35171] DLSBankManager.cpp:99 BankEntry::LoadInstrument: Unable to find patch 0 bank 0x78/0
2023-02-19 06:27:07.545255+0100 BlindMusic[596:35171] [default] DLSBankManager.cpp:100 about to throw -10851: LoadInstrument: Failed to load patch from bank
2023-02-19 06:27:07.545310+0100 BlindMusic[596:35171] GlobalState.cpp:486 DLS/SF2 bank load failed
and here is the code very simple
in the class I declare
class MusicScoreViewModel: ObservableObject {
let soundBankURL: URL = Bundle.main.url(forResource: "Full Grand Piano" , withExtension: "sf2")!
let midiSoundURL: URL = Bundle.main.url(forResource: "for_elise_by_beethoven" , withExtension: "mid")!
var midiPlayer: AVMIDIPlayer!
init() {
}
func playMidi() {
do {
midiPlayer = try AVMIDIPlayer(contentsOf: midiSoundURL, soundBankURL: soundBankURL)
midiPlayer.prepareToPlay()
midiPlayer.play {
print("finished playing")
}
} catch {
print("could not create MIDI player")
}
}
}
I appreciate any help thank you

Related

Select channels and subtitles in AVPlayer from m3u8 playlists on tvOS swift

Following the official documentation by Apple link
self.playerStatusObserver = player.observe(\.currentItem?.status, options: [.new,.old]{ (player, change) in
switch (player.status) {
case .readyToPlay:
player.appliesMediaSelectionCriteriaAutomatically = false
for characteristic in player.currentItem!.asset.availableMediaCharacteristicsWithMediaSelectionOptions {
print("\(characteristic)")
// Retrieve the AVMediaSelectionGroup for the specified characteristic.
if let group = player.currentItem!.asset.mediaSelectionGroup(forMediaCharacteristic: characteristic) {
// Print its options.
for option in group.options {
print(" Option: \(option.displayName)")
}
}
}
player.currentItem!.asset.availableMediaCharacteristicsWithMediaSelectionOptions has no items. Tried many cases, but player.currentItem?.tracks has only two tracks (video and audio), even if stream has more audio tracks.
How to select audio tracks and subtitles from a m3u8 stream, using standard AVPlayer and AVFoundation framework?
Your code relies on the current item being ready to play to access availableMediaCharacteristics. It could happen that availableMediaCharacteristics are actually still not available at that moment unless you created the player item with the property automaticallyLoadedAssetKeys parameter:
AVPlayerItem(asset: asset, automaticallyLoadedAssetKeys: ["availableMediaCharacteristicsWithMediaSelectionOptions"])
You can find further info about this on the following page:
https://developer.apple.com/documentation/avfoundation/avplayeritem/1388633-automaticallyloadedassetkeys
Depending on your use case you could also prefer loading the media characteristics asynchronously, you could do this with the following code:
func preloadAssetKeys() {
let key = "availableMediaCharacteristicsWithMediaSelectionOptions"
asset.loadValuesAsynchronously(forKeys: [key]) {
[weak self] in
guard let self = self else { return }
var error: NSError? = nil
switch self.asset.statusOfValue(forKey: key, error: &error) {
case .loaded:
// ℹ️ At this point is when availableMediaCharacteristics are actually available
()
default:
()
}
}
}

AVAsset.LoadValuesAsynchronously 0 tracks in completion handler with m3u8 URL

I am trying to prefetch video files with format m3u8 URL ending.
I run this code:
private func prefetch(for url: URL?) {
guard let url = url else { return nil }
let asset = assets[url] ?? AVAsset(url: url)
asset.loadValuesAsynchronously(forKeys: ["isPlayable", "tracks", "hasProtectedContent"], completionHandler: {
print("asset: \(url.relativeString) tracks: \(asset.tracks.count)")
})
assets[url] = asset // save to memory cache
}
Basically, it prints 0 tracks always in the asset.track.count print.
I would expect it to print 1-3 as it is the amount of tracks these videos have, and I do not see the performance in video playing is improved using this code.
Is there anything else I am missing to get those tracks prefetched?

WEBRTC How to capture video from camera library?

Can't load video from a UIImagePickerController using WebRTC.
With saved in-app Bundle file, it works, but if I use UIImagePickerController
UIImagePickerControllerDelegate.imagePickerController(_:didFinishPickingMediaWithInfo:))
so I use mediaInfo like this:
(info[.mediaURL] as! URL).path
This code I use to start capturing a video file
public func startCaptureLocalVideoFile(name: String, renderer: RTCVideoRenderer) {
print("startCaptureLocalVideoFile")
stopLocalCapture()
localRenderer = renderer
videoCapturer = RTCFileVideoCapturer(delegate: videoSource)
guard let capturer = videoCapturer as? RTCFileVideoCapturer else {
print("WebRTCService can't get capturer")
return
}
capturer.startCapturing(fromFileNamed: name) { error in
print("startCapturing error ", error)
return
}
localVideoTrack?.add(renderer)
}
so I get this media info:
info [__C.UIImagePickerControllerInfoKey(_rawValue: UIImagePickerControllerMediaURL): file:///private/var/mobile/Containers/Data/PluginKitPlugin/5F7A4469-5006-4590-8F59-396CD86A083B/tmp/trim.B46C5878-BAF2-432B-B627-9787D74CE7B0.MOV, __C.UIImagePickerControllerInfoKey(_rawValue: UIImagePickerControllerMediaType): public.movie, __C.UIImagePickerControllerInfoKey(_rawValue: UIImagePickerControllerReferenceURL): assets-library://asset/asset.MOV?id=33EECFB7-514A-435A-AA19-26A055FB9F06&ext=MOV]
and this error:
startCapturing error Error Domain=org.webrtc.RTCFileVideoCapturer Code=2001 "(null)" UserInfo={NSUnderlyingError=File /private/var/mobile/Containers/Data/PluginKitPlugin/5F7A4469-5006-4590-8F59-396CD86A083B/tmp/trim.B46C5878-BAF2-432B-B627-9787D74CE7B0.MOV not found in bundle}
Seems like it works with Bundle.main only, but we can't write to it.
Am I doing it right? Maybe there is another way to accomplish this?
Thanks for the help!

Some files in Documents subfolders cannot be access while device is locked / screen is off

Some files in Documents subfolders cannot be accessed while the device is locked.
AVAudioFile(forReading: currentPlaylistURLs[index!])
The above line will throw an error when the device is locked or screen is off and the URL is to some file in some subfolder in the Documents folder. Not all subfolders cause an error (Why??). When a device is unlocked there is no error. I noticed this behavior in iOS 13.2.3 so it was working fine prior to this version.
Error is:
[AVAudioFile.mm:134:AVAudioFileImpl: (ExtAudioFileOpenURL((CFURLRef)fileURL, &_extAudioFile)): error -54
Error Domain=com.apple.coreaudio.avfaudio Code=-54 "(null)" UserInfo={failed call=ExtAudioFileOpenURL((CFURLRef)fileURL, &_extAudioFile)}
Has anyone experience this?
You need to set your file's file protection key permission to .none and its parent folder as well:
extension URL {
var parentDirectory: URL? { try? resourceValues(forKeys: [.parentDirectoryURLKey]).parentDirectory }
var fileProtection: URLFileProtection? { try? resourceValues(forKeys: [.fileProtectionKey]).fileProtection }
func disableFileProtection() throws { try (self as NSURL).setResourceValue(URLFileProtection.none, forKey: .fileProtectionKey) }
}
let fileURL = URL.init(...)
if let parentDirectory = fileURL.parentDirectory {
do {
try parentDirectory.disableFileProtection()
try fileURL.disableFileProtection()
}
catch { print(error) }
}

AVMIDIPlayer DLSBankManager::AddBank: Bank load failed

When I use AVMIDIPlayer to play a MusicSequence with only one note message. Most of times it works fine but sometimes it has no sound and logged as below:
DLSBankManager::AddBank: Bank load failed
Error Domain=com.apple.coreaudio.avfaudio Code=-10871 "(null)"
It works well on iOS9, but when i test it on iOS10 it runs into this issue.
I'm sure that the sf2 sound bank file url is set properly.
I paste the code as below:
func playAVMIDIPlayerPreview(_ musicSequence:MusicSequence) {
guard let bankURL = Bundle.main.url(forResource: "FluidR3 GM2-2", withExtension: "sf2") else {
fatalError("soundbank file not found.")
}
var status = OSStatus(noErr)
var data:Unmanaged<CFData>?
status = MusicSequenceFileCreateData (musicSequence,
MusicSequenceFileTypeID.midiType,
MusicSequenceFileFlags.eraseFile,
480, &data)
if status != OSStatus(noErr) {
print("bad status \(status)")
}
if let md = data {
let midiData = md.takeUnretainedValue() as Data
do {
try self.midiPlayerPreview = AVMIDIPlayer(data: midiData, soundBankURL: bankURL)
} catch let error as NSError {
print("Error \(error)")
}
data?.release()
self.midiPlayerPreview?.play({ () -> Void in
self.midiPlayerPreview = nil
self.musicSequencePreview = nil
})
}
}
The error is occur on this line:
try self.midiPlayerPreview = AVMIDIPlayer(data: midiData, soundBankURL: bankURL)
Try setting the global variable errno to 0 errno = 0 before loading the soundfont with
try self.midiPlayerPreview = AVMIDIPlayer(data: midiData, soundBankURL: bankURL)
We experienced the same issue and at the same time this one.
So we tried to apply the fix of the other issue to this one and it just worked.