-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 15316fd
Showing
63 changed files
with
6,142 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
BassMidiAudioUnitHost/Soundfonts/Soundfont[[:space:]]-[[:space:]]FluidR3[[:space:]]GM[[:space:]](20011225).sf2 filter=lfs diff=lfs merge=lfs -text |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
# Xcode | ||
# | ||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore | ||
|
||
## User settings | ||
xcuserdata/ | ||
*.pbxuser | ||
|
||
# osx noise | ||
.DS_Store | ||
profile | ||
|
||
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) | ||
*.xcscmblueprint | ||
*.xccheckout | ||
|
||
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) | ||
build/ | ||
DerivedData/ | ||
*.moved-aside | ||
*.pbxuser | ||
!default.pbxuser | ||
*.mode1v3 | ||
!default.mode1v3 | ||
*.mode2v3 | ||
!default.mode2v3 | ||
*.perspectivev3 | ||
!default.perspectivev3 | ||
|
||
## Obj-C/Swift specific | ||
*.hmap | ||
|
||
## App packaging | ||
*.ipa | ||
*.dSYM.zip | ||
*.dSYM | ||
|
||
## Playgrounds | ||
timeline.xctimeline | ||
playground.xcworkspace | ||
|
||
# Swift Package Manager | ||
# | ||
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. | ||
# Packages/ | ||
# Package.pins | ||
# Package.resolved | ||
# *.xcodeproj | ||
# | ||
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata | ||
# hence it is not needed unless you have added a package configuration file to your project | ||
# .swiftpm | ||
|
||
.build/ | ||
|
||
# CocoaPods | ||
# | ||
# We recommend against adding the Pods directory to your .gitignore. However | ||
# you should judge for yourself, the pros and cons are mentioned at: | ||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control | ||
# | ||
# Pods/ | ||
# | ||
# Add this line if you want to avoid checking in source code from the Xcode workspace | ||
# *.xcworkspace | ||
|
||
# Carthage | ||
# | ||
# Add this line if you want to avoid checking in source code from Carthage dependencies. | ||
# Carthage/Checkouts | ||
|
||
Carthage/Build/ | ||
|
||
# Accio dependency management | ||
Dependencies/ | ||
.accio/ | ||
|
||
# fastlane | ||
# | ||
# It is recommended to not store the screenshots in the git repo. | ||
# Instead, use fastlane to re-generate the screenshots whenever they are needed. | ||
# For more information about the recommended setup visit: | ||
# https://docs.fastlane.tools/best-practices/source-control/#source-control | ||
|
||
fastlane/report.xml | ||
fastlane/Preview.html | ||
fastlane/screenshots/**/*.png | ||
fastlane/test_output | ||
|
||
# Code Injection | ||
# | ||
# After new code Injection tools there's a generated folder /iOSInjectionProject | ||
# https://github.com/johnno1962/injectionforxcode | ||
|
||
iOSInjectionProject/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// | ||
// BassMidiAudioUnit.h | ||
// BassMidi | ||
// | ||
// Created by Matthieu bouillaud on 17/03/2022. | ||
// | ||
|
||
#import <AudioToolbox/AudioToolbox.h> | ||
#import <BassMidiAudioUnitFramework/BassMidiDSPKernelAdapter.h> | ||
#import <AVFoundation/AVFoundation.h> | ||
|
||
@interface BassMidiAudioUnit : AUAudioUnit | ||
|
||
@property (nonatomic, readonly) BassMidiDSPKernelAdapter *kernelAdapter; | ||
- (void)setupAudioBuses; | ||
- (void)setupParameterTree; | ||
- (void)setupParameterCallbacks; | ||
+ (BOOL)initBassMidi:(UInt32)sampleRate; | ||
- (BOOL)loadSoundFont:(NSString*)path; | ||
|
||
@property (nonatomic) int32_t instrument; | ||
@property (nonatomic) int32_t transposition; | ||
@property (nonatomic) BOOL isMuted; | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
// | ||
// BassMidiAudioUnit.m | ||
// BassMidi | ||
// | ||
// Created by Matthieu bouillaud on 17/03/2022. | ||
// | ||
|
||
#import "BassMidiAudioUnit.h" | ||
#include <stdint.h> | ||
#include "bassmidi.h" | ||
|
||
@interface BassMidiAudioUnit () { | ||
int32_t _instrument; | ||
int32_t _transposition; | ||
BOOL _isMuted; | ||
} | ||
@property (nonatomic, readwrite) AUParameterTree *parameterTree; | ||
@property AUAudioUnitBusArray *inputBusArray; | ||
@property AUAudioUnitBusArray *outputBusArray; | ||
@end | ||
|
||
|
||
@implementation BassMidiAudioUnit | ||
@synthesize parameterTree = _parameterTree; | ||
|
||
#define kInvalidInstrumentCode -1 | ||
|
||
- (instancetype)initWithComponentDescription:(AudioComponentDescription)componentDescription options:(AudioComponentInstantiationOptions)options error:(NSError **)outError { | ||
self = [super initWithComponentDescription:componentDescription options:options error:outError]; | ||
|
||
if (self == nil) { return nil; } | ||
|
||
_kernelAdapter = [[BassMidiDSPKernelAdapter alloc] init]; | ||
_instrument = kInvalidInstrumentCode; | ||
_transposition = 0; | ||
_isMuted = NO; | ||
[self setupAudioBuses]; | ||
[self setupParameterTree]; | ||
[self setupParameterCallbacks]; | ||
return self; | ||
} | ||
|
||
#pragma mark - AUAudioUnit Setup | ||
|
||
+ (BOOL)initBassMidi:(UInt32)sampleRate { | ||
return BASS_Init(0, sampleRate, 0, NULL, NULL); | ||
} | ||
|
||
- (BOOL)loadSoundFont:(NSString*)filePath { | ||
NSLog(@"loadSoundFont = %@", filePath); | ||
return [_kernelAdapter prepareWithSoundFont:filePath]; | ||
} | ||
|
||
- (int32_t)instrument { | ||
return _instrument; | ||
} | ||
|
||
- (void)setInstrument:(int32_t)instrument { | ||
_instrument = instrument; | ||
[_kernelAdapter setInstrument: instrument]; | ||
} | ||
|
||
- (int32_t)transposition { | ||
return _transposition; | ||
} | ||
|
||
- (void)setTransposition:(int32_t)transposition { | ||
_transposition = transposition; | ||
[_kernelAdapter setTransposition:transposition]; | ||
} | ||
|
||
- (BOOL)isMuted { | ||
return _isMuted; | ||
} | ||
|
||
- (void)setIsMuted:(BOOL)isMuted { | ||
_isMuted = isMuted; | ||
[_kernelAdapter setIsMuted:isMuted]; | ||
} | ||
|
||
- (void)setupAudioBuses { | ||
// Create the input and output bus arrays. | ||
_inputBusArray = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self | ||
busType:AUAudioUnitBusTypeInput | ||
busses: @[_kernelAdapter.inputBus]]; | ||
_outputBusArray = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self | ||
busType:AUAudioUnitBusTypeOutput | ||
busses: @[_kernelAdapter.outputBus]]; | ||
} | ||
|
||
- (void)setupParameterTree { | ||
// Create parameter objects. | ||
} | ||
|
||
- (void)setupParameterCallbacks { | ||
// Make a local pointer to the kernel to avoid capturing self. | ||
__block BassMidiDSPKernelAdapter * kernelAdapter = _kernelAdapter; | ||
|
||
// implementorValueObserver is called when a parameter changes value. | ||
_parameterTree.implementorValueObserver = ^(AUParameter *param, AUValue value) { | ||
[kernelAdapter setParameter:param value:value]; | ||
}; | ||
|
||
// implementorValueProvider is called when the value needs to be refreshed. | ||
_parameterTree.implementorValueProvider = ^(AUParameter *param) { | ||
return [kernelAdapter valueForParameter:param]; | ||
}; | ||
|
||
// A function to provide string representations of parameter values. | ||
_parameterTree.implementorStringFromValueCallback = ^(AUParameter *param, const AUValue *__nullable valuePtr) { | ||
AUValue value = valuePtr == nil ? param.value : *valuePtr; | ||
|
||
return [NSString stringWithFormat:@"%.f", value]; | ||
}; | ||
} | ||
|
||
#pragma mark - AUAudioUnit Overrides | ||
|
||
- (AUAudioFrameCount)maximumFramesToRender { | ||
return _kernelAdapter.maximumFramesToRender; | ||
} | ||
|
||
- (void)setMaximumFramesToRender:(AUAudioFrameCount)maximumFramesToRender { | ||
_kernelAdapter.maximumFramesToRender = maximumFramesToRender; | ||
} | ||
|
||
// If an audio unit has input, an audio unit's audio input connection points. | ||
// Subclassers must override this property getter and should return the same object every time. | ||
// See sample code. | ||
- (AUAudioUnitBusArray *)inputBusses { | ||
return _inputBusArray; | ||
} | ||
|
||
// An audio unit's audio output connection points. | ||
// Subclassers must override this property getter and should return the same object every time. | ||
// See sample code. | ||
- (AUAudioUnitBusArray *)outputBusses { | ||
return _outputBusArray; | ||
} | ||
|
||
// Allocate resources required to render. | ||
// Subclassers should call the superclass implementation. | ||
- (BOOL)allocateRenderResourcesAndReturnError:(NSError **)outError { | ||
if (_kernelAdapter.outputBus.format.channelCount != _kernelAdapter.inputBus.format.channelCount) { | ||
if (outError) { | ||
*outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:kAudioUnitErr_FailedInitialization userInfo:nil]; | ||
} | ||
// Notify superclass that initialization was not successful | ||
self.renderResourcesAllocated = NO; | ||
|
||
return NO; | ||
} | ||
|
||
[super allocateRenderResourcesAndReturnError:outError]; | ||
_kernelAdapter.musicalContextBlock = self.musicalContextBlock; | ||
_kernelAdapter.MIDIOutBlock = self.MIDIOutputEventBlock; | ||
if (_instrument != kInvalidInstrumentCode) { | ||
[_kernelAdapter setInstrument:_instrument]; | ||
} | ||
[_kernelAdapter setTransposition:_transposition]; | ||
[_kernelAdapter setIsMuted:_isMuted]; | ||
[_kernelAdapter allocateRenderResources]; | ||
return YES; | ||
} | ||
|
||
// Deallocate resources allocated in allocateRenderResourcesAndReturnError: | ||
// Subclassers should call the superclass implementation. | ||
- (void)deallocateRenderResources { | ||
[_kernelAdapter deallocateRenderResources]; | ||
|
||
// Deallocate your resources. | ||
[super deallocateRenderResources]; | ||
} | ||
|
||
#pragma mark - AUAudioUnit (AUAudioUnitImplementation) | ||
|
||
// Block which subclassers must provide to implement rendering. | ||
- (AUInternalRenderBlock)internalRenderBlock { | ||
return _kernelAdapter.internalRenderBlock; | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import AVFoundation | ||
|
||
public struct BassMidiAudioUnitContainer { | ||
public let avAudioUnit: AVAudioUnit | ||
public let audioUnit: BassMidiAudioUnit | ||
} | ||
|
||
extension BassMidiAudioUnit { | ||
|
||
enum BassMidiAudioUnitError: Error { | ||
case unknown | ||
case soundFontLoading | ||
} | ||
|
||
private static let subtype: FourCharCode = "bass" | ||
private static let manufacturer: FourCharCode = "nwzk" | ||
private static let componentName = "nwzk: BassMidi" | ||
private static let version: UInt32 = UInt32.max | ||
private static var registered = false | ||
|
||
private static let componentDescription: AudioComponentDescription = { | ||
// Ensure that AudioUnit type, subtype, and manufacturer match the extension's Info.plist values. | ||
var componentDescription = AudioComponentDescription() | ||
componentDescription.componentType = kAudioUnitType_MusicDevice | ||
componentDescription.componentSubType = subtype | ||
componentDescription.componentManufacturer = manufacturer | ||
componentDescription.componentFlags = 0 | ||
componentDescription.componentFlagsMask = 0 | ||
return componentDescription | ||
}() | ||
|
||
private static func register() { | ||
guard !registered else { return } | ||
AUAudioUnit.registerSubclass(BassMidiAudioUnit.self, | ||
as: componentDescription, | ||
name: componentName, | ||
version: version) | ||
registered = true | ||
} | ||
|
||
public static func setup(sampleRate: UInt32) { | ||
initBassMidi(sampleRate) | ||
} | ||
|
||
public static func instantiate(soundFontPath: String, _ completion: @escaping (Result<BassMidiAudioUnitContainer, Error>) -> Void) { | ||
BassMidiAudioUnit.register() | ||
AVAudioUnit.instantiate(with: componentDescription, options: []) { unit, error in | ||
if let unit = unit, let bassMidiAudioUnit = unit.auAudioUnit as? BassMidiAudioUnit { | ||
let container = BassMidiAudioUnitContainer(avAudioUnit: unit, audioUnit: bassMidiAudioUnit) | ||
guard bassMidiAudioUnit.loadSoundFont(soundFontPath) else { | ||
completion(.failure(BassMidiAudioUnitError.soundFontLoading)) | ||
return | ||
} | ||
completion(.success(container)) | ||
} else if let error = error { | ||
completion(.failure(error)) | ||
} else { | ||
completion(.failure(BassMidiAudioUnitError.unknown)) | ||
} | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import Foundation | ||
import AVFoundation | ||
|
||
extension BassMidiAudioUnit { | ||
|
||
private func paramValue(address: AUParameterAddress) -> AUValue? { | ||
parameterTree?.parameter(withAddress: address)?.value | ||
} | ||
|
||
private func setParam(value: AUValue, address: AUParameterAddress) { | ||
parameterTree?.parameter(withAddress: address)?.value = value | ||
} | ||
|
||
} |
Oops, something went wrong.