123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050 |
- //
- // MidiPlayerEngine.m
- // MidiPlayer
- //
- // Created by Kyle on 2021/11/30.
- //
- #import "MidiPlayerEngine.h"
- #import <AVFoundation/AVFoundation.h>
- #import <CoreAudio/CoreAudioTypes.h>
- #import "CoreAudioUtils.h"
- #import "GCDTimer.h"
- @interface MidiPlayerEngine ()
- @property (readwrite) AUNode pitchNode;
- @property (readwrite) AudioUnit pitchUnit;
- @property (readwrite) AUGraph processingGraph;
- @property (readwrite) AUNode samplerNode;
- @property (readwrite) AUNode ioNode;
- @property (readwrite) AUNode mixerNode;
- @property (readwrite) AudioUnit samplerUnit;
- @property (readwrite) AudioUnit mixerUnit;
- @property (readwrite) AudioUnit ioUnit;
- @property (nonatomic) NSMutableArray* samplerNodeList;
- @property (nonatomic) NSMutableArray* samplerUnitList;
- @property (nonatomic) MusicPlayer musicPlayer;
- @property (nonatomic) MusicSequence musicSequence;
- @property (nonatomic) MusicTrack musicTrack;
- @property (nonatomic) UInt32 trackCount;
- @property (nonatomic) BOOL playing;
- @property (readwrite) double totalTime;
- @property (nonatomic) double currentTime;
- @property (nonatomic) Boolean isMute;
- @property (nonatomic) Boolean muteDrum;
- @property (nonatomic) NSMutableArray* instrumentArray;
- @property (nonatomic) double timeRatio;
- @property (nonatomic, strong) NSString *soundFileUrl;
- @property (nonatomic, strong) MidiPlayerEngine *clickPlayer;
- @property (nonatomic, assign) BOOL isClickPlayer;
- @property (nonatomic, assign) MusicTimeStamp trackLength;
- @property (nonatomic, strong) NSMutableDictionary *instrumentTrackParm; // 乐器编号对应轨道
- @end
- @implementation MidiPlayerEngine
- - (instancetype)init {
- self = [super init];
- if (self) {
- [self configDefault];
- }
- return self;
- }
- - (void)configDefault {
- self.isMute = NO;
- self.muteDrum = NO;
- self.baseRate = 120.0f;
- self.timeRatio = 1.0;
- self.reportTime = 10;
- self.soundFileUrl = [[NSBundle mainBundle]
- pathForResource:@"synthgms" ofType:@"sf2"];
- self.accompanyVolume = 0.2f;
- }
- - (void)configSoundFilePath:(NSString *)filePath {
- self.soundFileUrl = filePath;
- }
- #pragma mark ---- audio setup
- - (BOOL)createAUGraph {
- CheckError(NewAUGraph(&_processingGraph), "NewAUGraph");
-
- /*
- * 创建节点
- * 1.添加音频器附件描述
- * 2.音频处理图根据器件描述生成1个节点
- * 节点数= track数
- */
- AudioComponentDescription desc = {0};
- desc.componentType = kAudioUnitType_MusicDevice;
- /* MIDI合成器,多声道附件*/
- desc.componentSubType = kAudioUnitSubType_MIDISynth;
- desc.componentManufacturer = kAudioUnitManufacturer_Apple;
- desc.componentFlags = 0;
- desc.componentFlagsMask = 0;
- for (int i = 0; i < self.trackCount; i++) {
- CheckError(AUGraphAddNode(self.processingGraph, &desc, &_samplerNode), "AUGraphAddNode");
- [self.samplerNodeList addObject:[NSString stringWithFormat:@"%d", (int)_samplerNode]];
-
- }
- /*
- * 创建混合器节点
- */
- AudioComponentDescription mixerUnitDescription = {0};
- mixerUnitDescription.componentType = kAudioUnitType_Mixer;
- mixerUnitDescription.componentSubType = kAudioUnitSubType_MultiChannelMixer;
- mixerUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
- mixerUnitDescription.componentFlags = 0;
- mixerUnitDescription.componentFlagsMask = 0;
-
- CheckError(AUGraphAddNode(self.processingGraph,
- &mixerUnitDescription,
- &_mixerNode),
- "AUGraphAddNode");
- // I/O unit
- /*
- 创建输出节点
- */
- AudioComponentDescription iOUnitDescription = {0};
- iOUnitDescription.componentType = kAudioUnitType_Output;
- iOUnitDescription.componentSubType = kAudioUnitSubType_RemoteIO;
- iOUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
- iOUnitDescription.componentFlags = 0;
- iOUnitDescription.componentFlagsMask = 0;
-
- CheckError(AUGraphAddNode(self.processingGraph,
- &iOUnitDescription,
- &_ioNode),
- "AUGraphAddNode");
-
- // 变调
- AudioComponentDescription pitchDesc = {0};
- pitchDesc.componentType = kAudioUnitType_FormatConverter;
- pitchDesc.componentSubType = kAudioUnitSubType_NewTimePitch;
- pitchDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
- pitchDesc.componentFlags = 0;
- pitchDesc.componentFlagsMask = 0;
- AUGraphAddNode(self.processingGraph, &pitchDesc, &_pitchNode);
-
-
- /*
- 打开AUGraph才能调用AUGraphNodeInfo获取节点对应的audio unit
- */
- CheckError(AUGraphOpen(self.processingGraph), "AUGraphOpen");
-
-
- /*
- 保存sampler对应的audio unit
- */
- for(int i = 0; i< self.trackCount; i++){
- CAudioUnit* sampleUnit = [[CAudioUnit alloc] init];
- AudioUnit audioUnit = sampleUnit.audioUnit;
- CheckError(AUGraphNodeInfo(self.processingGraph,
- [self.samplerNodeList[i] intValue],
- NULL,
- &audioUnit),
- "AUGraphNodeInfo");
- [self configMaxFramesPerSliceWithAudioUnit:audioUnit];
- sampleUnit.audioUnit = audioUnit;
- [self.samplerUnitList addObject:sampleUnit];
-
-
- NSURL *bankURL;
- /*
- 音色库
- */
- bankURL = [[NSURL alloc] initFileURLWithPath:self.soundFileUrl];
-
- // load sound bank
- CheckError(AudioUnitSetProperty(audioUnit,
- kMusicDeviceProperty_SoundBankURL,
- kAudioUnitScope_Global,
- 0,
- &bankURL,
- sizeof(bankURL)),
- "kAUSamplerProperty_LoadPresetFromBank");
- }
-
- /*
- 保存mixer对应的audio unit
- */
- CheckError(AUGraphNodeInfo(self.processingGraph,
- self.mixerNode,
- NULL,
- &_mixerUnit),
- "AUGraphNodeInfo");
- [self configMaxFramesPerSliceWithAudioUnit:_mixerUnit];
- /*
- 保存输出对应的audio unit
- */
- CheckError(AUGraphNodeInfo(self.processingGraph,
- self.ioNode,
- NULL,
- &_ioUnit),
- "AUGraphNodeInfo");
-
- [self configMaxFramesPerSliceWithAudioUnit:_ioUnit];
-
- /*
- 设置mixer输入的数量
- */
- UInt32 busCount = self.trackCount;
- //set the mixer unit`s bus count
- CheckError(AudioUnitSetProperty(_mixerUnit,
- kAudioUnitProperty_ElementCount,
- kAudioUnitScope_Input,
- 0,
- &busCount,
- sizeof(busCount)),
- "AudioUnitSetProperty_SetMixerInputCount");
- /*
- 设置mixer的采样率,44.1kHz是标准采样率
- */
- Float64 graphSampleRate = 44100.0;
- //set mixer unit`s output sample rate format
- CheckError(AudioUnitSetProperty(_mixerUnit,
- kAudioUnitProperty_SampleRate,
- kAudioUnitScope_Output,
- 0,
- &graphSampleRate,
- sizeof(graphSampleRate)),
- "AudioUnitSetProperty_SetMixerSampleRate");
-
- AudioUnitParameterValue defaultOutputVolume = 1.0;
- CheckError(AudioUnitSetParameter(_mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Output, 0, defaultOutputVolume, 0), "AudioUnitSetParameter(kMultiChannelMixerParam_Volume)");
-
-
- //connect samplers to mixer unit
- /*
- 将sampler unit的输出连到mixer的输入
- */
- for(int i = 0;i < self.trackCount;i++) {
- CheckError(AUGraphConnectNodeInput(self.processingGraph,
- [self.samplerNodeList[i] intValue],
- 0,
- self.mixerNode,
- i),
- "AUGraphConnectNodeInput_ConnectSamplersToMixerUnit");
- }
-
-
- /*
- 保存pitchNode对应的audio unit
- */
- AUGraphNodeInfo(self.processingGraph, self.pitchNode, &pitchDesc, &_pitchUnit);
- [self configMaxFramesPerSliceWithAudioUnit:_pitchUnit];
-
- AUGraphConnectNodeInput(self.processingGraph, self.mixerNode, 0, self.pitchNode, 0);
-
- //connect pitch to output unit
- /*
- 将pitch的输出连到remote I/O的输入
- */
- CheckError(AUGraphConnectNodeInput(self.processingGraph,
- self.pitchNode,
- 0,
- self.ioNode,
- 0),
- "AUGraphConnectNodeInput_ConnectMixerToOutput");
-
-
-
- NSLog (@"AUGraph is configured");
-
- return YES;
- }
- - (void)configMaxFramesPerSliceWithAudioUnit:(AudioUnit)audioUnit {
- AVAudioFrameCount maxFramesPerSlice = 4096;
- CheckError(AudioUnitSetProperty(audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFramesPerSlice, sizeof(maxFramesPerSlice)),"kAudioUnitProperty_MaximumFramesPerSlice");
- }
- - (void)startGraph {
- /*
- 音频处理图的初始化和开启
- */
- if (self.processingGraph) {
- Boolean outIsInitialized;
- CheckError(AUGraphIsInitialized(self.processingGraph,
- &outIsInitialized), "AUGraphIsInitialized");
- if(!outIsInitialized)
- CheckError(AUGraphInitialize(self.processingGraph), "AUGraphInitialize");
-
- Boolean isRunning;
- CheckError(AUGraphIsRunning(self.processingGraph,
- &isRunning), "AUGraphIsRunning");
- if(!isRunning)
- CheckError(AUGraphStart(self.processingGraph), "AUGraphStart");
- }
- }
- - (void)stopAUGraph {
-
- NSLog (@"Stopping audio processing graph");
- Boolean isRunning = false;
- CheckError(AUGraphIsRunning (self.processingGraph, &isRunning), "AUGraphIsRunning");
-
- if (isRunning) {
- CheckError(AUGraphStop(self.processingGraph), "AUGraphStop");
- self.playing = NO;
- }
- }
- - (void)setupAudioSession {
-
- AVAudioSession *audioSession = [AVAudioSession sharedInstance];
- NSError *err = nil;
- AVAudioSessionCategory category = AVAudioSessionCategoryPlayAndRecord;
- if (@available(iOS 10.0, *)) {
- [audioSession setCategory:category mode:AVAudioSessionModeDefault options:AVAudioSessionCategoryOptionAllowBluetooth|AVAudioSessionCategoryOptionAllowBluetoothA2DP|AVAudioSessionCategoryOptionDefaultToSpeaker|AVAudioSessionCategoryOptionMixWithOthers error:&err];
- }
- else {
- [audioSession setCategory:category withOptions:AVAudioSessionCategoryOptionAllowBluetooth|AVAudioSessionCategoryOptionDefaultToSpeaker|AVAudioSessionCategoryOptionMixWithOthers error:&err];
- }
- [audioSession setActive:YES error:&err];
- }
- - (void)resumeAUGraph {
- if (self.processingGraph) {
- [self stopAUGraph];
- Boolean isRunning;
- CheckError(AUGraphIsRunning(self.processingGraph,
- &isRunning), "AUGraphIsRunning");
- if(!isRunning) {
- CheckError(AUGraphStart(self.processingGraph), "AUGraphStart");
- }
- }
- }
- #pragma mark --- Audio control
- - (BOOL)loadMIDIFileWithString:(NSString *)filePath {
- // 判断文件是否存在
- BOOL isExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
- if (isExist) {
- NSURL* midiFileURL = [[NSURL alloc] initFileURLWithPath:filePath];
- //新建MusicSequence
- CheckError(NewMusicSequence(&_musicSequence), "NewMusicSequence");
- NSData *midi_data = [NSData dataWithContentsOfURL:midiFileURL];
- //把文件加载到MusicSequence
- NSLog(@"----- start load file");
- // 提高加载速度 kMusicSequenceLoadSMF_ChannelsToTracks 会合并轨道 导致轨道速可能减少
- CheckError(MusicSequenceFileLoadData(self.musicSequence, (__bridge CFDataRef)midi_data, kMusicSequenceFile_MIDIType, kMusicSequenceLoadSMF_PreserveTracks), "MusicSequenceFileLoad");
- // NSLog(@"----- end load file");
- // CheckError(MusicSequenceFileLoad(self.musicSequence,
- // (__bridge CFURLRef) midiFileURL,
- // 0,
- // kMusicSequenceLoadSMF_ChannelsToTracks), "MusicSequenceFileLoad");
- NSLog(@"----- end load file");
-
- //读取MIDI文件轨道数量
- CheckError(MusicSequenceGetTrackCount(self.musicSequence, &_trackCount), "MusicSequenceGetTrackCount");
- NSLog(@"track ----%d",self.trackCount);
- [self createAUGraph];
- [self startGraph];
-
- CheckError(NewMusicPlayer(&_musicPlayer), "NewMusicPlayer");
-
- CheckError(MusicPlayerSetSequence(self.musicPlayer, self.musicSequence), "MusicPlayerSetSequence");
-
- //关联Sequence和AUGraph
- CheckError(MusicSequenceSetAUGraph(self.musicSequence, self.processingGraph),
- "MusicSequenceSetAUGraph");
-
- // 获取速度
- [self getTempoMessage];
-
- MusicTrack track;
- MusicTimeStamp maxTrackLength = 0;
- self.instrumentTrackNameArray = [NSMutableArray array];
- self.baseInstrumentArray = [NSMutableArray array];
- for (int i = 0; i < self.trackCount; i++) {
- CheckError(MusicSequenceGetIndTrack (self.musicSequence, i, &track), "MusicSequenceGetIndTrack");
-
- MusicTimeStamp track_length;
- UInt32 tracklength_size = sizeof(MusicTimeStamp);
- CheckError(MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, &track_length, &tracklength_size), "kSequenceTrackProperty_TrackLength");
- MusicTimeStamp track_offset = 0;
- UInt32 trackoffset_size = sizeof(track_offset);
- CheckError(MusicTrackGetProperty(track, kSequenceTrackProperty_OffsetTime, &track_offset, &trackoffset_size), "kSequenceTrackProperty_OffsetTime_TrackOffset");
-
- MusicTimeStamp trackLength = track_length + track_offset;
- if(trackLength>maxTrackLength) maxTrackLength = trackLength;
-
- MusicTrackLoopInfo loopInfo;
- UInt32 lisize = sizeof(MusicTrackLoopInfo);
- CheckError(MusicTrackGetProperty(track,kSequenceTrackProperty_LoopInfo, &loopInfo, &lisize ), "kSequenceTrackProperty_LoopInfo");
- NSLog(@"Loop info: duration %f", loopInfo.loopDuration);
-
- [self iterate:track TrackIndex:i];
-
- CheckError(MusicTrackSetDestNode(track, [self.samplerNodeList[i] intValue]), "MusicTrackSetDestNode");
- }
- self.trackLength = maxTrackLength;
- // 获取总时长
- CheckError(MusicSequenceGetSecondsForBeats(self.musicSequence, maxTrackLength, &_totalTime), "MusicSequenceGetSecondsForBeats");
- NSLog(@"Music total time is: %f",self.totalTime);
-
- __weak typeof(self) weakSelf=self;
- dispatch_async(dispatch_get_main_queue(), ^{
- if([weakSelf.delegate respondsToSelector:@selector(GetMusicTotalTime:)]){
- [weakSelf.delegate GetMusicTotalTime:weakSelf.totalTime];
- }
- });
-
- /*
- 播放准备
- */
- self.currentTime = 0;
- // 初始化成功回调
- dispatch_async(dispatch_get_main_queue(), ^{
- if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(initPlayerEngineSuccess:)]) {
- [weakSelf.delegate initPlayerEngineSuccess:weakSelf.totalTime];
- }
- });
-
- return YES;
- }
- else {
- NSLog(@"文件不存在 !!!");
- return NO;
- }
- }
- - (void)getTempoMessage {
-
- OSStatus result = noErr;
- MusicTrack tempoTrack;
- result = MusicSequenceGetTempoTrack(self.musicSequence, &tempoTrack);
- if (noErr != result) { // 未获取到tempo轨道
- NSLog(@"MusicSequenceGetTempoTrack, %d", (int)result);
- return;
- }
-
- MusicEventIterator iterator;
- CheckError(NewMusicEventIterator(tempoTrack, &iterator), "NewMusicEventIterator");
-
- MusicEventType eventType;
- MusicTimeStamp eventTimeStamp;
- UInt32 eventDataSize;
- const void *eventData;
- Boolean hasCurrentEvent = NO;
-
- CheckError(MusicEventIteratorHasCurrentEvent(iterator, &hasCurrentEvent), "MusicEventIteratorHasCurrentEvent");
-
- while (hasCurrentEvent) {
- MusicEventIteratorGetEventInfo(iterator, &eventTimeStamp, &eventType, &eventData, &eventDataSize);
- switch (eventType) {
- case kMusicEventType_ExtendedTempo: // 速度
- {
- ExtendedTempoEvent *ext_tempo_evt = (ExtendedTempoEvent*)eventData;
- NSLog(@"ExtendedTempoEvent, bpm %f", ext_tempo_evt->bpm);
- self.baseRate = ext_tempo_evt->bpm;
- }
- break;
-
- default:
- break;
- }
- CheckError(MusicEventIteratorHasNextEvent(iterator, &hasCurrentEvent), "MusicEventIteratorHasCurrentEvent");
- CheckError(MusicEventIteratorNextEvent(iterator), "MusicEventIteratorNextEvent");
- }
- }
- // 读取track 的event信息
- - (void)iterate:(MusicTrack)track TrackIndex:(int)index {
- MusicEventIterator iterator;
- CheckError(NewMusicEventIterator(track, &iterator), "NewMusicEventIterator");
-
- MusicEventType eventType;
- MusicTimeStamp eventTimeStamp;
- UInt32 eventDataSize;
- const void *eventData;
-
- Boolean hasCurrentEvent = NO;
- BOOL hasRecordTrackInstrument = NO; // 是否记录了对应轨道的乐器 该判断是为了防止中途存在替换乐器的情况改变了记录的情况
- CheckError(MusicEventIteratorHasCurrentEvent(iterator, &hasCurrentEvent), "MusicEventIteratorHasCurrentEvent");
- while (hasCurrentEvent)
- {
- MusicEventIteratorGetEventInfo(iterator, &eventTimeStamp, &eventType, &eventData, &eventDataSize);
- // NSLog(@"event timeStamp %f ", eventTimeStamp);
- switch (eventType) {
-
- case kMusicEventType_ExtendedNote : {
-
- }
- break;
-
- case kMusicEventType_ExtendedTempo : { // 速度
-
- // ExtendedTempoEvent* ext_tempo_evt = (ExtendedTempoEvent*)eventData;
- // NSLog(@"ExtendedTempoEvent, bpm %f", ext_tempo_evt->bpm);
- // self.baseRate = ext_tempo_evt->bpm;
- }
- break;
-
- case kMusicEventType_User : {
- // MusicEventUserData* user_evt = (MusicEventUserData*)eventData;
- // NSLog(@"MusicEventUserData, data length %u", (unsigned int)user_evt->length);
- }
- break;
-
- case kMusicEventType_Meta : {
- MIDIMetaEvent* meta_evt = (MIDIMetaEvent*)eventData;
- // NSLog(@"MIDIMetaEvent, event type %d", meta_evt->metaEventType);
- if (meta_evt->metaEventType == 0x03) { // 音序或 track 的名称
-
- NSString *name = [[NSString alloc] initWithBytes:meta_evt->data length:meta_evt->dataLength encoding:NSUTF8StringEncoding];
- name = [[name componentsSeparatedByString:@","] lastObject];
- name = [name replaceAll:@"\0" WithString:@""];
- // NSLog(@"------- name -----%@",name);
- [self.instrumentTrackNameArray addObject:name];
- }
- }
- break;
-
- case kMusicEventType_MIDINoteMessage : { // 音符信息
- // MIDINoteMessage* note_evt = (MIDINoteMessage*)eventData;
- // NSLog(@"note event channel %d", note_evt->channel);
- // NSLog(@"note event note %d", note_evt->note);
- // NSLog(@"note event duration %f", note_evt->duration);
- // NSLog(@"note event velocity %d", note_evt->velocity);
- }
- break;
-
- case kMusicEventType_MIDIChannelMessage : { // channel message
- MIDIChannelMessage* channel_evt = (MIDIChannelMessage*)eventData;
-
- if((channel_evt->status& 0xF0) == 0xC0 ) {
-
- NSLog(@"-- track index %d ------ instrument %d ", index, channel_evt->data1);
- UInt32 instrumentId = channel_evt->data1;
- if (hasRecordTrackInstrument == NO) {
- // 0 ~ 7 都为钢琴
- if (instrumentId >= 0 && instrumentId <= 7) {
- instrumentId = 0;
- }
- NSString *instruemntKey = [NSString stringWithFormat:@"%d",instrumentId];
- NSMutableArray *valueArray = [NSMutableArray array];
- if ([[self.instrumentTrackParm allKeys] containsObject:instruemntKey]) {
- valueArray = [self.instrumentTrackParm ks_mutableArrayValueForKey:instruemntKey];
- }
-
- [valueArray addObject:@(index)];
- [self.instrumentTrackParm setValue:valueArray forKey:instruemntKey];
- hasRecordTrackInstrument = YES;
- }
-
- // /*
- // 静音处理
- // */
- // Boolean isSet = NO; /* 判断轨道是否设置静音 */
- // if (self.isMute){
- //
- // for (int i = 0; i < self.instrumentArray.count; i++){
- // int instrument = [self.instrumentArray[i] intValue];
- // if(channel_evt->data1 == instrument){
- // isSet = YES;
- // CheckError(MusicTrackSetProperty(track, kSequenceTrackProperty_MuteStatus, &_isMute, sizeof(_isMute)), "SetMusicTrackMute");
- // }
- // }
- //
- // }
- // if (self.muteDrum && ((channel_evt->status& 0x0F) == 9)){
- // isSet = YES;
- // CheckError(MusicTrackSetProperty(track, kSequenceTrackProperty_MuteStatus, &_muteDrum, sizeof(_muteDrum)), "SetMusicTrackMuteDrum");
- // }
- }
- else if ((channel_evt->status& 0xF0) == 0xB7) { // 音量控制
- // NSLog(@"channel event status %X", channel_evt->status);
- // NSLog(@"channel event d1 %X", channel_evt->data1);
- // NSLog(@"channel event d2 %X", channel_evt->data2);
- }
- else {
- // NSLog(@"channel event status %X", channel_evt->status);
- // NSLog(@"channel event d1 %X", channel_evt->data1);
- // NSLog(@"channel event d2 %X", channel_evt->data2);
- }
- }
- break ;
-
- case kMusicEventType_MIDIRawData : {
- // MIDIRawData* raw_data_evt = (MIDIRawData*)eventData;
- // NSLog(@"MIDIRawData, length %lu", raw_data_evt->length);
- }
- break ;
-
- case kMusicEventType_Parameter : {
- // ParameterEvent* parameter_evt = (ParameterEvent*)eventData;
- // NSLog(@"ParameterEvent, parameterid %lu", parameter_evt->parameterID);
- }
- break ;
-
- default :
- break ;
- }
-
- CheckError(MusicEventIteratorHasNextEvent(iterator, &hasCurrentEvent), "MusicEventIteratorHasCurrentEvent");
- CheckError(MusicEventIteratorNextEvent(iterator), "MusicEventIteratorNextEvent");
- }
- }
- /* 根据轨道名称获取单个轨道的编号*/
- - (NSInteger)getSingleTrackNumByName:(NSString *)trackName {
-
- for (NSInteger i = 0; i < self.instrumentTrackNameArray.count; i++) {
- NSString *instrumentTrackName = self.instrumentTrackNameArray[i];
- if ([trackName isEqualToString:instrumentTrackName]) {
- return i;
- }
- }
- return -1;
- }
- /* 通过轨道名称获取对应的轨道*/
- - (NSMutableArray *)getTrackNumerFromName:(NSArray *)trackNameArray {
- NSMutableArray *trackArray = [NSMutableArray array];
- NSLog(@"%@",self.instrumentTrackNameArray);
- for (NSString *name in trackNameArray) {
- for (NSInteger i = 0; i < self.instrumentTrackNameArray.count; i++) {
- NSString *instrumentTrackName = self.instrumentTrackNameArray[i];
- // 包含name就添加对应的轨道
- if ([name isEqualToString:instrumentTrackName]) {
- [trackArray addObject:@(i)];
- }
- }
- }
- return trackArray;
- }
- /**根据乐器编号获取所在轨道*/
- - (NSMutableArray *)getTrackWithInstrumentId:(UInt32)instrumentId {
- NSString *key = [NSString stringWithFormat:@"%d",instrumentId];
- return [self.instrumentTrackParm ks_mutableArrayValueForKey:key];
- }
- /**设置对应乐器编号所在轨道的播放音量*/
- - (BOOL)volumeTrackVolumeWithInstrumentId:(UInt32)instrumentId volume:(float)volume {
- NSArray *instrumentArray = [self.instrumentTrackParm allKeys];
- if (instrumentArray.count < 2) {
- return NO;
- }
- // 0~7都是钢琴 全都取0
- if (instrumentId >= 0 && instrumentId <= 7) {
- instrumentId = 0;
- }
- NSMutableArray *trackArray = [self.instrumentTrackParm ks_mutableArrayValueForKey:[NSString stringWithFormat:@"%d",instrumentId]];
- if (trackArray.count) {
- for (NSInteger index = 0; index < trackArray.count; index++) {
- UInt32 track = [trackArray[index] intValue];
- [self volume:volume WithTrack:track];
- }
- }
- return YES;
- }
- - (void)muteTrackWithTrackNameExclude:(NSMutableArray *)trackNameArray {
- NSMutableArray *unMuteArray = [self getTrackNumerFromName:trackNameArray];
- for (UInt32 i = 0; i < self.trackCount; i++) {
- Boolean mutedBoolean = true;
- MusicTrack track;
- MusicSequenceGetIndTrack(self.musicSequence, i, &track);
- MusicTrackSetProperty(track, kSequenceTrackProperty_MuteStatus, &mutedBoolean, sizeof(mutedBoolean));
- }
-
- Boolean mutedBoolean = FALSE;
- for (NSNumber *trackNo in unMuteArray) {
- MusicTrack track;
- MusicSequenceGetIndTrack(self.musicSequence, trackNo.intValue, &track);
- MusicTrackSetProperty(track, kSequenceTrackProperty_MuteStatus, &mutedBoolean, sizeof(mutedBoolean));
- }
- }
- // 播放mid文件
- - (void)playMIDIFile {
-
- CheckError(MusicPlayerPreroll(self.musicPlayer), "MusicPlayerPreroll");
-
- CheckError(MusicPlayerSetPlayRateScalar(self.musicPlayer, self.timeRatio), "MusicPlayerSetPlayRateScalar");
-
- CheckError(MusicPlayerStart(self.musicPlayer), "MusicPlayerStart");
- self.playing = YES;
-
- __weak typeof(self) weakSelf = self;
- dispatch_queue_t queue = dispatch_queue_create("Timer", DISPATCH_QUEUE_SERIAL);
- // 定时器回调
- [[GCDTimer shared] scheduleGCDTimerWithName:@"MusicPlayerTimer" Interval:self.reportTime Queue:queue Repeats:YES Action:^{
-
- MusicTimeStamp currentStamp;
- CheckError(MusicPlayerGetTime(weakSelf.musicPlayer, ¤tStamp), "MusicPlayerGetTime_CurrentTimeStamp");
- double currentPlayTime;
- CheckError(MusicSequenceGetSecondsForBeats(weakSelf.musicSequence, currentStamp, ¤tPlayTime), "MusicSequencself->GetSecondsForBeats_CurrentTime");
- weakSelf.currentTime = currentPlayTime;
-
- if (weakSelf.currentTime >= weakSelf.totalTime) {
- weakSelf.currentTime = weakSelf.totalTime;
- dispatch_async(dispatch_get_main_queue(), ^{
- if ([weakSelf.delegate respondsToSelector:@selector(playEnd)]) {
- [weakSelf.delegate playEnd];
- }
- // 进度上报100%
- if([weakSelf.delegate respondsToSelector:@selector(ProgressUpdated:currentTime:)]) {
- [weakSelf.delegate ProgressUpdated:weakSelf.currentTime/weakSelf.totalTime currentTime:weakSelf.currentTime];
- }
- });
-
- [[GCDTimer shared] cancelAllTimer];
- CheckError(MusicPlayerStop(weakSelf.musicPlayer), "MusicPlayerStop");
-
- weakSelf.playing = NO;
- weakSelf.currentTime = 0;
- CheckError(MusicSequenceGetBeatsForSeconds(weakSelf.musicSequence, weakSelf.currentTime, ¤tStamp), "MusicSequenceGetBeatsForSeconds_SetCurrentStamp");
- CheckError(MusicPlayerSetTime(weakSelf.musicPlayer, currentStamp), "MusicPlayerSetTime_SetZero");
- }
- else {
- // 如果是选段播放 到结束
- if (weakSelf.endTime != 0 && weakSelf.currentTime >= weakSelf.endTime) {
- dispatch_async(dispatch_get_main_queue(), ^{
- if ([weakSelf.delegate respondsToSelector:@selector(playEnd)]) {
- [weakSelf.delegate playEnd];
- }
- });
-
- [[GCDTimer shared] cancelAllTimer];
- CheckError(MusicPlayerStop(weakSelf.musicPlayer), "MusicPlayerStop");
-
- weakSelf.playing = NO;
- weakSelf.currentTime = 0;
- CheckError(MusicSequenceGetBeatsForSeconds(weakSelf.musicSequence, weakSelf.currentTime, ¤tStamp), "MusicSequenceGetBeatsForSeconds_SetCurrentStamp");
- CheckError(MusicPlayerSetTime(weakSelf.musicPlayer, currentStamp), "MusicPlayerSetTime_SetZero");
- }
- else {
- dispatch_async(dispatch_get_main_queue(), ^{
- if ([weakSelf.delegate respondsToSelector:@selector(ProgressUpdated:currentTime:)]){
- [weakSelf.delegate ProgressUpdated:weakSelf.currentTime/weakSelf.totalTime currentTime:weakSelf.currentTime];
- }
- });
- }
- }
- }];
- }
- - (void)stopPlayingMIDIFile {
- CheckError(MusicPlayerStop(self.musicPlayer), "MusicPlayerStop");
- self.playing = NO;
- [[GCDTimer shared] cancelAllTimer];
- }
- - (BOOL)setMusicPlayerSpeed:(double)speed {
- if(speed<0) return NO;
- else {
- self.timeRatio = speed;
- if (self.musicPlayer){
- CheckError(MusicPlayerSetPlayRateScalar(self.musicPlayer, self.timeRatio), "MusicPlayerSetPlayRateScalar");
- }
- return YES;
- }
- }
- - (void)setProgress:(double)progress {
- if(progress>1||progress<0) return;
-
- self.currentTime = self.totalTime * progress;
- MusicTimeStamp currentStamp;
- CheckError(MusicSequenceGetBeatsForSeconds(self.musicSequence, self.currentTime, ¤tStamp), "MusicSequenceGetBeatsForSeconds_SetCurrentStamp");
- CheckError(MusicPlayerSetTime(self.musicPlayer, currentStamp), "MusicPlayerSetTime_SetZero");
-
- // [self stopPlayingMIDIFile];
- }
- - (void)setProgressTime:(MusicTimeStamp)startTime {
- if (startTime < 0 || startTime > self.totalTime) {
- return;
- }
- self.currentTime = startTime;
- MusicTimeStamp currentStamp;
- CheckError(MusicSequenceGetBeatsForSeconds(self.musicSequence, self.currentTime, ¤tStamp), "MusicSequenceGetBeatsForSeconds_SetCurrentStamp");
- CheckError(MusicPlayerSetTime(self.musicPlayer, currentStamp), "MusicPlayerSetTime_SetZero");
- // [self stopPlayingMIDIFile];
- }
- - (void)muteWithInstrument:(UInt8)instrument {
- if(instrument<0||instrument>127) return;
-
- NSNumber* numIns = [NSNumber numberWithInt:instrument];
- [self.instrumentArray addObject:numIns];
-
- self.isMute = YES;
- }
- -(void)muteWithDrum {
- self.muteDrum = YES;
- }
- -(BOOL)isPlayingFile {
- return self.playing;
- }
- -(double)musicTotalTime {
- return self.totalTime;
- }
- -(double)musicCurrentTime {
- return self.currentTime;
- }
- - (void)volume:(float)volume WithTrack:(UInt32)trackNum {
-
- if(volume<0||volume>1) return;
- if(trackNum<0||trackNum>self.trackCount) return;
- CheckError(AudioUnitSetParameter(_mixerUnit,
- kMultiChannelMixerParam_Volume,
- kAudioUnitScope_Input,
- trackNum,
- volume,
- 0),
- "AudioUnitSetMixerInputVolume");
- }
- /* 调整除了 trackNum 之外的 其他轨道的音量 范围[0,1]*/
- - (void)volumeOtherTrackExcept:(UInt32)trackNum withVolume:(float)volume {
- if(volume<0||volume>1) return;
- if(trackNum<0||trackNum>self.trackCount) return;
-
- CheckError(AudioUnitSetParameter(_mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Input, trackNum, 1, 0), "AudioUnitSetMixerInputVolume");
- }
- - (void)getAllTrackVolume {
- for (int i = 0; i < self.trackCount; i++) {
- float volume = 0.0f;
- AudioUnitGetParameter(_mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Input, i, &volume);
- NSLog(@"------ track %d --- volume :%.2f", i, volume);
- }
- }
- - (void)muteTrack:(BOOL)isMute WithTrack:(NSMutableArray *)trackArray {
-
- Boolean mutedBoolean = isMute ? TRUE : FALSE;
- for (NSNumber *trackNo in trackArray) {
- MusicTrack track;
- MusicSequenceGetIndTrack(self.musicSequence, trackNo.intValue, &track);
- MusicTrackSetProperty(track, kSequenceTrackProperty_MuteStatus, &mutedBoolean, sizeof(mutedBoolean));
- }
- }
- - (void)cleanup {
- if (self.musicPlayer) {
- //当前在播放,先暂停
- if ([self isPlayingFile]) {
- [self stopPlayingMIDIFile];
- }
- CheckError(MusicSequenceGetTrackCount(self.musicSequence, &_trackCount), "MusicSequenceGetTrackCount");
- MusicTrack track;
- for (int i = 0;i < self.trackCount; i++) {
- CheckError(MusicSequenceGetIndTrack (self.musicSequence,0,&track), "MusicSequenceGetIndTrack");
- CheckError(MusicSequenceDisposeTrack(self.musicSequence, track), "MusicSequenceDisposeTrack");
- }
-
- CheckError(DisposeMusicPlayer(self.musicPlayer), "DisposeMusicPlayer");
- CheckError(DisposeMusicSequence(self.musicSequence), "DisposeMusicSequence");
- CheckError(DisposeAUGraph(self.processingGraph), "DisposeAUGraph");
-
- self.playing=NO;
-
- [self.samplerNodeList removeAllObjects];
- [self.samplerUnitList removeAllObjects];
- [self.instrumentArray removeAllObjects];
- [self.instrumentTrackNameArray removeAllObjects];
-
- self.isMute = NO;
- self.muteDrum = NO;
- NSLog(@"CleanUp!");
- }
- }
- #pragma mark ------ 变调 调整hz
- - (void)transformTo442Hz {
- [self adjustPitchByHZ:442.0f];
- }
- // hz调整 440 - 442。。。。。。。
- - (void)adjustPitchByHZ:(float)newHZ {
- // 415 ~ 466
- if (newHZ < 415 || newHZ > 466) {
- return;
- }
- /**
- 1200音分等于一个八度音程,频率比为2:1,等程半音(相当于相邻钢琴键间的音程)等于100音分。这意味着1音分正好等于21/1200,即
- 如果知道两个音a和b的频率,两个音相距的音分值n可用下列公式计算(类似分贝定义式的形式,目的是为了使指数形式的物理单位线性化,使其化为对数):
- n=1200 *log2(a/b) == 3986 *log10(a/b)
- */
- Float32 censt = log2(newHZ/440.0) * 1200;
- AudioUnitSetParameter(self.pitchUnit, kNewTimePitchParam_Pitch, kAudioUnitScope_Global, 0, censt, 0);
- }
- #pragma mark ---- 自动循环功能和播放时同步节拍器暂未实现
- - (void)startPlaybackLoop {
- self.isLooping = YES;
- [self startPlaybackFromPosition:0];
- }
- - (void)startPlaybackFromPosition:(MusicTimeStamp)position {
- if (self.playing) {
- [self stopPlayback];
- }
- [self loopTrackWhenNeed];
- [self addClickTrackWhenNeededFromTimeStamp:position];
-
- // CheckError(<#OSStatus error#>, <#const char *operation#>)
- }
- #pragma mark ---- Looping
- - (void)loopTrackWhenNeed {
- if (self.isLooping) {
- MusicTrackLoopInfo loopInfo;
- loopInfo.numberOfLoops = 0;
- loopInfo.loopDuration = self.trackLength;
- MusicTrack track;
- // 设置循环播放属性
- for (int i = 0; i < self.trackCount; i++) {
- CheckError(MusicSequenceGetIndTrack (self.musicSequence, i, &track), "MusicSequenceGetIndTrack");
- CheckError(MusicTrackSetProperty(track, kSequenceTrackProperty_LoopInfo, &loopInfo, sizeof(loopInfo)), "MusicTrackSetProperty loop");
- }
- }
- }
- #pragma mark ----- click tracks
- - (void)addClickTrackWhenNeededFromTimeStamp:(MusicTimeStamp)fromTimeStamp {
- if (self.isClickPlayer) {
- return;
- }
- if (self.isClickTrackEnabled == NO) {
- return;
- }
-
- self.clickPlayer = [[MidiPlayerEngine alloc] init];
- self.clickPlayer->_isClickPlayer = YES;
-
- // 添加节拍器mid声轨
-
- }
- #pragma mark --- Properties
- - (void)setIsLooping:(BOOL)isLooping {
- if (isLooping != _isLooping) {
- _isLooping = isLooping;
- if (self.playing) { // 如果正在播放 停止之后从新开启播放
-
- }
- }
- }
- #pragma mark --- Lazyload
- - (NSMutableArray*)samplerNodeList {
- if (!_samplerNodeList) {
- _samplerNodeList = [[NSMutableArray alloc] init];
- }
- return _samplerNodeList;
- }
- - (NSMutableArray*)samplerUnitList {
- if (!_samplerUnitList) {
- _samplerUnitList = [[NSMutableArray alloc] init];
- }
- return _samplerUnitList;
- }
- -(NSMutableArray*)instrumentArray {
- if (!_instrumentArray) {
- _instrumentArray = [[NSMutableArray alloc] init];
- }
- return _instrumentArray;
- }
- - (NSMutableArray *)muteTrackArray {
- if (!_muteTrackArray) {
- _muteTrackArray = [NSMutableArray array];
- }
- return _muteTrackArray;
- }
- - (NSMutableDictionary *)instrumentTrackParm {
- if (!_instrumentTrackParm) {
- _instrumentTrackParm = [NSMutableDictionary dictionary];
- }
- return _instrumentTrackParm;
- }
- - (void)dealloc {
- NSLog(@"************ player engine dealloc!");
- }
- /*
- 物理连接
- ____________
- | |
- | Sampler |-------
- | | |
- ------------ |
- |
- ____________ | ---------------------- ------------
- | | ----->| | | |
- | Sampler |------------->| MultiChannel Mixer |------------->| I/O |
- | | ----->| | | |
- ------------ | ---------------------- ------------
- |
- ____________ |
- | | |
- | Sampler |-------
- | |
- ------------
-
-
-
-
-
-
- --------------------- -------------------------------------------------
- | MusicSequence | | AUGraph |
- | | | |
- | MusicTrack1 ---|--------| ->MIDISynth1 |
- | | | --->MixerNode -------> OutputNode|
- | MusicTrack2 ---|--------| ->MIDISynth2 |
- | | | |
- --------------------- -------------------------------------------------
-
-
- */
- @end
|