MidiPlayerEngine.m 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
  1. //
  2. // MidiPlayerEngine.m
  3. // MidiPlayer
  4. //
  5. // Created by Kyle on 2021/11/30.
  6. //
  7. #import "MidiPlayerEngine.h"
  8. #import <AVFoundation/AVFoundation.h>
  9. #import <CoreAudio/CoreAudioTypes.h>
  10. #import "CoreAudioUtils.h"
  11. #import "GCDTimer.h"
  12. @interface MidiPlayerEngine ()
  13. @property (readwrite) AUNode pitchNode;
  14. @property (readwrite) AudioUnit pitchUnit;
  15. @property (readwrite) AUGraph processingGraph;
  16. @property (readwrite) AUNode samplerNode;
  17. @property (readwrite) AUNode ioNode;
  18. @property (readwrite) AUNode mixerNode;
  19. @property (readwrite) AudioUnit samplerUnit;
  20. @property (readwrite) AudioUnit mixerUnit;
  21. @property (readwrite) AudioUnit ioUnit;
  22. @property (nonatomic) NSMutableArray* samplerNodeList;
  23. @property (nonatomic) NSMutableArray* samplerUnitList;
  24. @property (nonatomic) MusicPlayer musicPlayer;
  25. @property (nonatomic) MusicSequence musicSequence;
  26. @property (nonatomic) MusicTrack musicTrack;
  27. @property (nonatomic) UInt32 trackCount;
  28. @property (nonatomic) BOOL playing;
  29. @property (readwrite) double totalTime;
  30. @property (nonatomic) double currentTime;
  31. @property (nonatomic) Boolean isMute;
  32. @property (nonatomic) Boolean muteDrum;
  33. @property (nonatomic) NSMutableArray* instrumentArray;
  34. @property (nonatomic) double timeRatio;
  35. @property (nonatomic, strong) NSString *soundFileUrl;
  36. @property (nonatomic, strong) MidiPlayerEngine *clickPlayer;
  37. @property (nonatomic, assign) BOOL isClickPlayer;
  38. @property (nonatomic, assign) MusicTimeStamp trackLength;
  39. @property (nonatomic, strong) NSMutableDictionary *instrumentTrackParm; // 乐器编号对应轨道
  40. @end
  41. @implementation MidiPlayerEngine
  42. - (instancetype)init {
  43. self = [super init];
  44. if (self) {
  45. [self configDefault];
  46. }
  47. return self;
  48. }
  49. - (void)configDefault {
  50. self.isMute = NO;
  51. self.muteDrum = NO;
  52. self.baseRate = 120.0f;
  53. self.timeRatio = 1.0;
  54. self.reportTime = 10;
  55. self.soundFileUrl = [[NSBundle mainBundle]
  56. pathForResource:@"synthgms" ofType:@"sf2"];
  57. self.accompanyVolume = 0.2f;
  58. }
  59. - (void)configSoundFilePath:(NSString *)filePath {
  60. self.soundFileUrl = filePath;
  61. }
  62. #pragma mark ---- audio setup
  63. - (BOOL)createAUGraph {
  64. CheckError(NewAUGraph(&_processingGraph), "NewAUGraph");
  65. /*
  66. * 创建节点
  67. * 1.添加音频器附件描述
  68. * 2.音频处理图根据器件描述生成1个节点
  69. * 节点数= track数
  70. */
  71. AudioComponentDescription desc = {0};
  72. desc.componentType = kAudioUnitType_MusicDevice;
  73. /* MIDI合成器,多声道附件*/
  74. desc.componentSubType = kAudioUnitSubType_MIDISynth;
  75. desc.componentManufacturer = kAudioUnitManufacturer_Apple;
  76. desc.componentFlags = 0;
  77. desc.componentFlagsMask = 0;
  78. for (int i = 0; i < self.trackCount; i++) {
  79. CheckError(AUGraphAddNode(self.processingGraph, &desc, &_samplerNode), "AUGraphAddNode");
  80. [self.samplerNodeList addObject:[NSString stringWithFormat:@"%d", (int)_samplerNode]];
  81. }
  82. /*
  83. * 创建混合器节点
  84. */
  85. AudioComponentDescription mixerUnitDescription = {0};
  86. mixerUnitDescription.componentType = kAudioUnitType_Mixer;
  87. mixerUnitDescription.componentSubType = kAudioUnitSubType_MultiChannelMixer;
  88. mixerUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
  89. mixerUnitDescription.componentFlags = 0;
  90. mixerUnitDescription.componentFlagsMask = 0;
  91. CheckError(AUGraphAddNode(self.processingGraph,
  92. &mixerUnitDescription,
  93. &_mixerNode),
  94. "AUGraphAddNode");
  95. // I/O unit
  96. /*
  97. 创建输出节点
  98. */
  99. AudioComponentDescription iOUnitDescription = {0};
  100. iOUnitDescription.componentType = kAudioUnitType_Output;
  101. iOUnitDescription.componentSubType = kAudioUnitSubType_RemoteIO;
  102. iOUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
  103. iOUnitDescription.componentFlags = 0;
  104. iOUnitDescription.componentFlagsMask = 0;
  105. CheckError(AUGraphAddNode(self.processingGraph,
  106. &iOUnitDescription,
  107. &_ioNode),
  108. "AUGraphAddNode");
  109. // 变调
  110. AudioComponentDescription pitchDesc = {0};
  111. pitchDesc.componentType = kAudioUnitType_FormatConverter;
  112. pitchDesc.componentSubType = kAudioUnitSubType_NewTimePitch;
  113. pitchDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
  114. pitchDesc.componentFlags = 0;
  115. pitchDesc.componentFlagsMask = 0;
  116. AUGraphAddNode(self.processingGraph, &pitchDesc, &_pitchNode);
  117. /*
  118. 打开AUGraph才能调用AUGraphNodeInfo获取节点对应的audio unit
  119. */
  120. CheckError(AUGraphOpen(self.processingGraph), "AUGraphOpen");
  121. /*
  122. 保存sampler对应的audio unit
  123. */
  124. for(int i = 0; i< self.trackCount; i++){
  125. CAudioUnit* sampleUnit = [[CAudioUnit alloc] init];
  126. AudioUnit audioUnit = sampleUnit.audioUnit;
  127. CheckError(AUGraphNodeInfo(self.processingGraph,
  128. [self.samplerNodeList[i] intValue],
  129. NULL,
  130. &audioUnit),
  131. "AUGraphNodeInfo");
  132. [self configMaxFramesPerSliceWithAudioUnit:audioUnit];
  133. sampleUnit.audioUnit = audioUnit;
  134. [self.samplerUnitList addObject:sampleUnit];
  135. NSURL *bankURL;
  136. /*
  137. 音色库
  138. */
  139. bankURL = [[NSURL alloc] initFileURLWithPath:self.soundFileUrl];
  140. // load sound bank
  141. CheckError(AudioUnitSetProperty(audioUnit,
  142. kMusicDeviceProperty_SoundBankURL,
  143. kAudioUnitScope_Global,
  144. 0,
  145. &bankURL,
  146. sizeof(bankURL)),
  147. "kAUSamplerProperty_LoadPresetFromBank");
  148. }
  149. /*
  150. 保存mixer对应的audio unit
  151. */
  152. CheckError(AUGraphNodeInfo(self.processingGraph,
  153. self.mixerNode,
  154. NULL,
  155. &_mixerUnit),
  156. "AUGraphNodeInfo");
  157. [self configMaxFramesPerSliceWithAudioUnit:_mixerUnit];
  158. /*
  159. 保存输出对应的audio unit
  160. */
  161. CheckError(AUGraphNodeInfo(self.processingGraph,
  162. self.ioNode,
  163. NULL,
  164. &_ioUnit),
  165. "AUGraphNodeInfo");
  166. [self configMaxFramesPerSliceWithAudioUnit:_ioUnit];
  167. /*
  168. 设置mixer输入的数量
  169. */
  170. UInt32 busCount = self.trackCount;
  171. //set the mixer unit`s bus count
  172. CheckError(AudioUnitSetProperty(_mixerUnit,
  173. kAudioUnitProperty_ElementCount,
  174. kAudioUnitScope_Input,
  175. 0,
  176. &busCount,
  177. sizeof(busCount)),
  178. "AudioUnitSetProperty_SetMixerInputCount");
  179. /*
  180. 设置mixer的采样率,44.1kHz是标准采样率
  181. */
  182. Float64 graphSampleRate = 44100.0;
  183. //set mixer unit`s output sample rate format
  184. CheckError(AudioUnitSetProperty(_mixerUnit,
  185. kAudioUnitProperty_SampleRate,
  186. kAudioUnitScope_Output,
  187. 0,
  188. &graphSampleRate,
  189. sizeof(graphSampleRate)),
  190. "AudioUnitSetProperty_SetMixerSampleRate");
  191. AudioUnitParameterValue defaultOutputVolume = 1.0;
  192. CheckError(AudioUnitSetParameter(_mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Output, 0, defaultOutputVolume, 0), "AudioUnitSetParameter(kMultiChannelMixerParam_Volume)");
  193. //connect samplers to mixer unit
  194. /*
  195. 将sampler unit的输出连到mixer的输入
  196. */
  197. for(int i = 0;i < self.trackCount;i++) {
  198. CheckError(AUGraphConnectNodeInput(self.processingGraph,
  199. [self.samplerNodeList[i] intValue],
  200. 0,
  201. self.mixerNode,
  202. i),
  203. "AUGraphConnectNodeInput_ConnectSamplersToMixerUnit");
  204. }
  205. /*
  206. 保存pitchNode对应的audio unit
  207. */
  208. AUGraphNodeInfo(self.processingGraph, self.pitchNode, &pitchDesc, &_pitchUnit);
  209. [self configMaxFramesPerSliceWithAudioUnit:_pitchUnit];
  210. AUGraphConnectNodeInput(self.processingGraph, self.mixerNode, 0, self.pitchNode, 0);
  211. //connect pitch to output unit
  212. /*
  213. 将pitch的输出连到remote I/O的输入
  214. */
  215. CheckError(AUGraphConnectNodeInput(self.processingGraph,
  216. self.pitchNode,
  217. 0,
  218. self.ioNode,
  219. 0),
  220. "AUGraphConnectNodeInput_ConnectMixerToOutput");
  221. NSLog (@"AUGraph is configured");
  222. return YES;
  223. }
  224. - (void)configMaxFramesPerSliceWithAudioUnit:(AudioUnit)audioUnit {
  225. AVAudioFrameCount maxFramesPerSlice = 4096;
  226. CheckError(AudioUnitSetProperty(audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFramesPerSlice, sizeof(maxFramesPerSlice)),"kAudioUnitProperty_MaximumFramesPerSlice");
  227. }
  228. - (void)startGraph {
  229. /*
  230. 音频处理图的初始化和开启
  231. */
  232. if (self.processingGraph) {
  233. Boolean outIsInitialized;
  234. CheckError(AUGraphIsInitialized(self.processingGraph,
  235. &outIsInitialized), "AUGraphIsInitialized");
  236. if(!outIsInitialized)
  237. CheckError(AUGraphInitialize(self.processingGraph), "AUGraphInitialize");
  238. Boolean isRunning;
  239. CheckError(AUGraphIsRunning(self.processingGraph,
  240. &isRunning), "AUGraphIsRunning");
  241. if(!isRunning)
  242. CheckError(AUGraphStart(self.processingGraph), "AUGraphStart");
  243. }
  244. }
  245. - (void)stopAUGraph {
  246. NSLog (@"Stopping audio processing graph");
  247. Boolean isRunning = false;
  248. CheckError(AUGraphIsRunning (self.processingGraph, &isRunning), "AUGraphIsRunning");
  249. if (isRunning) {
  250. CheckError(AUGraphStop(self.processingGraph), "AUGraphStop");
  251. self.playing = NO;
  252. }
  253. }
  254. - (void)setupAudioSession {
  255. AVAudioSession *audioSession = [AVAudioSession sharedInstance];
  256. NSError *err = nil;
  257. AVAudioSessionCategory category = AVAudioSessionCategoryPlayAndRecord;
  258. if (@available(iOS 10.0, *)) {
  259. [audioSession setCategory:category mode:AVAudioSessionModeDefault options:AVAudioSessionCategoryOptionAllowBluetooth|AVAudioSessionCategoryOptionAllowBluetoothA2DP|AVAudioSessionCategoryOptionDefaultToSpeaker|AVAudioSessionCategoryOptionMixWithOthers error:&err];
  260. }
  261. else {
  262. [audioSession setCategory:category withOptions:AVAudioSessionCategoryOptionAllowBluetooth|AVAudioSessionCategoryOptionDefaultToSpeaker|AVAudioSessionCategoryOptionMixWithOthers error:&err];
  263. }
  264. [audioSession setActive:YES error:&err];
  265. }
  266. - (void)resumeAUGraph {
  267. if (self.processingGraph) {
  268. [self stopAUGraph];
  269. Boolean isRunning;
  270. CheckError(AUGraphIsRunning(self.processingGraph,
  271. &isRunning), "AUGraphIsRunning");
  272. if(!isRunning) {
  273. CheckError(AUGraphStart(self.processingGraph), "AUGraphStart");
  274. }
  275. }
  276. }
  277. #pragma mark --- Audio control
  278. - (BOOL)loadMIDIFileWithString:(NSString *)filePath {
  279. // 判断文件是否存在
  280. BOOL isExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
  281. if (isExist) {
  282. NSURL* midiFileURL = [[NSURL alloc] initFileURLWithPath:filePath];
  283. //新建MusicSequence
  284. CheckError(NewMusicSequence(&_musicSequence), "NewMusicSequence");
  285. NSData *midi_data = [NSData dataWithContentsOfURL:midiFileURL];
  286. //把文件加载到MusicSequence
  287. NSLog(@"----- start load file");
  288. // 提高加载速度 kMusicSequenceLoadSMF_ChannelsToTracks 会合并轨道 导致轨道速可能减少
  289. CheckError(MusicSequenceFileLoadData(self.musicSequence, (__bridge CFDataRef)midi_data, kMusicSequenceFile_MIDIType, kMusicSequenceLoadSMF_PreserveTracks), "MusicSequenceFileLoad");
  290. // NSLog(@"----- end load file");
  291. // CheckError(MusicSequenceFileLoad(self.musicSequence,
  292. // (__bridge CFURLRef) midiFileURL,
  293. // 0,
  294. // kMusicSequenceLoadSMF_ChannelsToTracks), "MusicSequenceFileLoad");
  295. NSLog(@"----- end load file");
  296. //读取MIDI文件轨道数量
  297. CheckError(MusicSequenceGetTrackCount(self.musicSequence, &_trackCount), "MusicSequenceGetTrackCount");
  298. NSLog(@"track ----%d",self.trackCount);
  299. [self createAUGraph];
  300. [self startGraph];
  301. CheckError(NewMusicPlayer(&_musicPlayer), "NewMusicPlayer");
  302. CheckError(MusicPlayerSetSequence(self.musicPlayer, self.musicSequence), "MusicPlayerSetSequence");
  303. //关联Sequence和AUGraph
  304. CheckError(MusicSequenceSetAUGraph(self.musicSequence, self.processingGraph),
  305. "MusicSequenceSetAUGraph");
  306. // 获取速度
  307. [self getTempoMessage];
  308. MusicTrack track;
  309. MusicTimeStamp maxTrackLength = 0;
  310. self.instrumentTrackNameArray = [NSMutableArray array];
  311. self.baseInstrumentArray = [NSMutableArray array];
  312. for (int i = 0; i < self.trackCount; i++) {
  313. CheckError(MusicSequenceGetIndTrack (self.musicSequence, i, &track), "MusicSequenceGetIndTrack");
  314. MusicTimeStamp track_length;
  315. UInt32 tracklength_size = sizeof(MusicTimeStamp);
  316. CheckError(MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, &track_length, &tracklength_size), "kSequenceTrackProperty_TrackLength");
  317. MusicTimeStamp track_offset = 0;
  318. UInt32 trackoffset_size = sizeof(track_offset);
  319. CheckError(MusicTrackGetProperty(track, kSequenceTrackProperty_OffsetTime, &track_offset, &trackoffset_size), "kSequenceTrackProperty_OffsetTime_TrackOffset");
  320. MusicTimeStamp trackLength = track_length + track_offset;
  321. if(trackLength>maxTrackLength) maxTrackLength = trackLength;
  322. MusicTrackLoopInfo loopInfo;
  323. UInt32 lisize = sizeof(MusicTrackLoopInfo);
  324. CheckError(MusicTrackGetProperty(track,kSequenceTrackProperty_LoopInfo, &loopInfo, &lisize ), "kSequenceTrackProperty_LoopInfo");
  325. NSLog(@"Loop info: duration %f", loopInfo.loopDuration);
  326. [self iterate:track TrackIndex:i];
  327. CheckError(MusicTrackSetDestNode(track, [self.samplerNodeList[i] intValue]), "MusicTrackSetDestNode");
  328. }
  329. self.trackLength = maxTrackLength;
  330. // 获取总时长
  331. CheckError(MusicSequenceGetSecondsForBeats(self.musicSequence, maxTrackLength, &_totalTime), "MusicSequenceGetSecondsForBeats");
  332. NSLog(@"Music total time is: %f",self.totalTime);
  333. __weak typeof(self) weakSelf=self;
  334. dispatch_async(dispatch_get_main_queue(), ^{
  335. if([weakSelf.delegate respondsToSelector:@selector(GetMusicTotalTime:)]){
  336. [weakSelf.delegate GetMusicTotalTime:weakSelf.totalTime];
  337. }
  338. });
  339. /*
  340. 播放准备
  341. */
  342. self.currentTime = 0;
  343. // 初始化成功回调
  344. dispatch_async(dispatch_get_main_queue(), ^{
  345. if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(initPlayerEngineSuccess:)]) {
  346. [weakSelf.delegate initPlayerEngineSuccess:weakSelf.totalTime];
  347. }
  348. });
  349. return YES;
  350. }
  351. else {
  352. NSLog(@"文件不存在 !!!");
  353. return NO;
  354. }
  355. }
  356. - (void)getTempoMessage {
  357. OSStatus result = noErr;
  358. MusicTrack tempoTrack;
  359. result = MusicSequenceGetTempoTrack(self.musicSequence, &tempoTrack);
  360. if (noErr != result) { // 未获取到tempo轨道
  361. NSLog(@"MusicSequenceGetTempoTrack, %d", (int)result);
  362. return;
  363. }
  364. MusicEventIterator iterator;
  365. CheckError(NewMusicEventIterator(tempoTrack, &iterator), "NewMusicEventIterator");
  366. MusicEventType eventType;
  367. MusicTimeStamp eventTimeStamp;
  368. UInt32 eventDataSize;
  369. const void *eventData;
  370. Boolean hasCurrentEvent = NO;
  371. CheckError(MusicEventIteratorHasCurrentEvent(iterator, &hasCurrentEvent), "MusicEventIteratorHasCurrentEvent");
  372. while (hasCurrentEvent) {
  373. MusicEventIteratorGetEventInfo(iterator, &eventTimeStamp, &eventType, &eventData, &eventDataSize);
  374. switch (eventType) {
  375. case kMusicEventType_ExtendedTempo: // 速度
  376. {
  377. ExtendedTempoEvent *ext_tempo_evt = (ExtendedTempoEvent*)eventData;
  378. NSLog(@"ExtendedTempoEvent, bpm %f", ext_tempo_evt->bpm);
  379. self.baseRate = ext_tempo_evt->bpm;
  380. }
  381. break;
  382. default:
  383. break;
  384. }
  385. CheckError(MusicEventIteratorHasNextEvent(iterator, &hasCurrentEvent), "MusicEventIteratorHasCurrentEvent");
  386. CheckError(MusicEventIteratorNextEvent(iterator), "MusicEventIteratorNextEvent");
  387. }
  388. }
  389. // 读取track 的event信息
  390. - (void)iterate:(MusicTrack)track TrackIndex:(int)index {
  391. MusicEventIterator iterator;
  392. CheckError(NewMusicEventIterator(track, &iterator), "NewMusicEventIterator");
  393. MusicEventType eventType;
  394. MusicTimeStamp eventTimeStamp;
  395. UInt32 eventDataSize;
  396. const void *eventData;
  397. Boolean hasCurrentEvent = NO;
  398. BOOL hasRecordTrackInstrument = NO; // 是否记录了对应轨道的乐器 该判断是为了防止中途存在替换乐器的情况改变了记录的情况
  399. CheckError(MusicEventIteratorHasCurrentEvent(iterator, &hasCurrentEvent), "MusicEventIteratorHasCurrentEvent");
  400. while (hasCurrentEvent)
  401. {
  402. MusicEventIteratorGetEventInfo(iterator, &eventTimeStamp, &eventType, &eventData, &eventDataSize);
  403. // NSLog(@"event timeStamp %f ", eventTimeStamp);
  404. switch (eventType) {
  405. case kMusicEventType_ExtendedNote : {
  406. }
  407. break;
  408. case kMusicEventType_ExtendedTempo : { // 速度
  409. // ExtendedTempoEvent* ext_tempo_evt = (ExtendedTempoEvent*)eventData;
  410. // NSLog(@"ExtendedTempoEvent, bpm %f", ext_tempo_evt->bpm);
  411. // self.baseRate = ext_tempo_evt->bpm;
  412. }
  413. break;
  414. case kMusicEventType_User : {
  415. // MusicEventUserData* user_evt = (MusicEventUserData*)eventData;
  416. // NSLog(@"MusicEventUserData, data length %u", (unsigned int)user_evt->length);
  417. }
  418. break;
  419. case kMusicEventType_Meta : {
  420. MIDIMetaEvent* meta_evt = (MIDIMetaEvent*)eventData;
  421. // NSLog(@"MIDIMetaEvent, event type %d", meta_evt->metaEventType);
  422. if (meta_evt->metaEventType == 0x03) { // 音序或 track 的名称
  423. NSString *name = [[NSString alloc] initWithBytes:meta_evt->data length:meta_evt->dataLength encoding:NSUTF8StringEncoding];
  424. name = [[name componentsSeparatedByString:@","] lastObject];
  425. name = [name replaceAll:@"\0" WithString:@""];
  426. // NSLog(@"------- name -----%@",name);
  427. [self.instrumentTrackNameArray addObject:name];
  428. }
  429. }
  430. break;
  431. case kMusicEventType_MIDINoteMessage : { // 音符信息
  432. // MIDINoteMessage* note_evt = (MIDINoteMessage*)eventData;
  433. // NSLog(@"note event channel %d", note_evt->channel);
  434. // NSLog(@"note event note %d", note_evt->note);
  435. // NSLog(@"note event duration %f", note_evt->duration);
  436. // NSLog(@"note event velocity %d", note_evt->velocity);
  437. }
  438. break;
  439. case kMusicEventType_MIDIChannelMessage : { // channel message
  440. MIDIChannelMessage* channel_evt = (MIDIChannelMessage*)eventData;
  441. if((channel_evt->status& 0xF0) == 0xC0 ) {
  442. NSLog(@"-- track index %d ------ instrument %d ", index, channel_evt->data1);
  443. UInt32 instrumentId = channel_evt->data1;
  444. if (hasRecordTrackInstrument == NO) {
  445. // 0 ~ 7 都为钢琴
  446. if (instrumentId >= 0 && instrumentId <= 7) {
  447. instrumentId = 0;
  448. }
  449. NSString *instruemntKey = [NSString stringWithFormat:@"%d",instrumentId];
  450. NSMutableArray *valueArray = [NSMutableArray array];
  451. if ([[self.instrumentTrackParm allKeys] containsObject:instruemntKey]) {
  452. valueArray = [self.instrumentTrackParm ks_mutableArrayValueForKey:instruemntKey];
  453. }
  454. [valueArray addObject:@(index)];
  455. [self.instrumentTrackParm setValue:valueArray forKey:instruemntKey];
  456. hasRecordTrackInstrument = YES;
  457. }
  458. // /*
  459. // 静音处理
  460. // */
  461. // Boolean isSet = NO; /* 判断轨道是否设置静音 */
  462. // if (self.isMute){
  463. //
  464. // for (int i = 0; i < self.instrumentArray.count; i++){
  465. // int instrument = [self.instrumentArray[i] intValue];
  466. // if(channel_evt->data1 == instrument){
  467. // isSet = YES;
  468. // CheckError(MusicTrackSetProperty(track, kSequenceTrackProperty_MuteStatus, &_isMute, sizeof(_isMute)), "SetMusicTrackMute");
  469. // }
  470. // }
  471. //
  472. // }
  473. // if (self.muteDrum && ((channel_evt->status& 0x0F) == 9)){
  474. // isSet = YES;
  475. // CheckError(MusicTrackSetProperty(track, kSequenceTrackProperty_MuteStatus, &_muteDrum, sizeof(_muteDrum)), "SetMusicTrackMuteDrum");
  476. // }
  477. }
  478. else if ((channel_evt->status& 0xF0) == 0xB7) { // 音量控制
  479. // NSLog(@"channel event status %X", channel_evt->status);
  480. // NSLog(@"channel event d1 %X", channel_evt->data1);
  481. // NSLog(@"channel event d2 %X", channel_evt->data2);
  482. }
  483. else {
  484. // NSLog(@"channel event status %X", channel_evt->status);
  485. // NSLog(@"channel event d1 %X", channel_evt->data1);
  486. // NSLog(@"channel event d2 %X", channel_evt->data2);
  487. }
  488. }
  489. break ;
  490. case kMusicEventType_MIDIRawData : {
  491. // MIDIRawData* raw_data_evt = (MIDIRawData*)eventData;
  492. // NSLog(@"MIDIRawData, length %lu", raw_data_evt->length);
  493. }
  494. break ;
  495. case kMusicEventType_Parameter : {
  496. // ParameterEvent* parameter_evt = (ParameterEvent*)eventData;
  497. // NSLog(@"ParameterEvent, parameterid %lu", parameter_evt->parameterID);
  498. }
  499. break ;
  500. default :
  501. break ;
  502. }
  503. CheckError(MusicEventIteratorHasNextEvent(iterator, &hasCurrentEvent), "MusicEventIteratorHasCurrentEvent");
  504. CheckError(MusicEventIteratorNextEvent(iterator), "MusicEventIteratorNextEvent");
  505. }
  506. }
  507. /* 根据轨道名称获取单个轨道的编号*/
  508. - (NSInteger)getSingleTrackNumByName:(NSString *)trackName {
  509. for (NSInteger i = 0; i < self.instrumentTrackNameArray.count; i++) {
  510. NSString *instrumentTrackName = self.instrumentTrackNameArray[i];
  511. if ([trackName isEqualToString:instrumentTrackName]) {
  512. return i;
  513. }
  514. }
  515. return -1;
  516. }
  517. /* 通过轨道名称获取对应的轨道*/
  518. - (NSMutableArray *)getTrackNumerFromName:(NSArray *)trackNameArray {
  519. NSMutableArray *trackArray = [NSMutableArray array];
  520. NSLog(@"%@",self.instrumentTrackNameArray);
  521. for (NSString *name in trackNameArray) {
  522. for (NSInteger i = 0; i < self.instrumentTrackNameArray.count; i++) {
  523. NSString *instrumentTrackName = self.instrumentTrackNameArray[i];
  524. // 包含name就添加对应的轨道
  525. if ([name isEqualToString:instrumentTrackName]) {
  526. [trackArray addObject:@(i)];
  527. }
  528. }
  529. }
  530. return trackArray;
  531. }
  532. /**根据乐器编号获取所在轨道*/
  533. - (NSMutableArray *)getTrackWithInstrumentId:(UInt32)instrumentId {
  534. NSString *key = [NSString stringWithFormat:@"%d",instrumentId];
  535. return [self.instrumentTrackParm ks_mutableArrayValueForKey:key];
  536. }
  537. /**设置对应乐器编号所在轨道的播放音量*/
  538. - (BOOL)volumeTrackVolumeWithInstrumentId:(UInt32)instrumentId volume:(float)volume {
  539. NSArray *instrumentArray = [self.instrumentTrackParm allKeys];
  540. if (instrumentArray.count < 2) {
  541. return NO;
  542. }
  543. // 0~7都是钢琴 全都取0
  544. if (instrumentId >= 0 && instrumentId <= 7) {
  545. instrumentId = 0;
  546. }
  547. NSMutableArray *trackArray = [self.instrumentTrackParm ks_mutableArrayValueForKey:[NSString stringWithFormat:@"%d",instrumentId]];
  548. if (trackArray.count) {
  549. for (NSInteger index = 0; index < trackArray.count; index++) {
  550. UInt32 track = [trackArray[index] intValue];
  551. [self volume:volume WithTrack:track];
  552. }
  553. }
  554. return YES;
  555. }
  556. - (void)muteTrackWithTrackNameExclude:(NSMutableArray *)trackNameArray {
  557. NSMutableArray *unMuteArray = [self getTrackNumerFromName:trackNameArray];
  558. for (UInt32 i = 0; i < self.trackCount; i++) {
  559. Boolean mutedBoolean = true;
  560. MusicTrack track;
  561. MusicSequenceGetIndTrack(self.musicSequence, i, &track);
  562. MusicTrackSetProperty(track, kSequenceTrackProperty_MuteStatus, &mutedBoolean, sizeof(mutedBoolean));
  563. }
  564. Boolean mutedBoolean = FALSE;
  565. for (NSNumber *trackNo in unMuteArray) {
  566. MusicTrack track;
  567. MusicSequenceGetIndTrack(self.musicSequence, trackNo.intValue, &track);
  568. MusicTrackSetProperty(track, kSequenceTrackProperty_MuteStatus, &mutedBoolean, sizeof(mutedBoolean));
  569. }
  570. }
  571. // 播放mid文件
  572. - (void)playMIDIFile {
  573. CheckError(MusicPlayerPreroll(self.musicPlayer), "MusicPlayerPreroll");
  574. CheckError(MusicPlayerSetPlayRateScalar(self.musicPlayer, self.timeRatio), "MusicPlayerSetPlayRateScalar");
  575. CheckError(MusicPlayerStart(self.musicPlayer), "MusicPlayerStart");
  576. self.playing = YES;
  577. __weak typeof(self) weakSelf = self;
  578. dispatch_queue_t queue = dispatch_queue_create("Timer", DISPATCH_QUEUE_SERIAL);
  579. // 定时器回调
  580. [[GCDTimer shared] scheduleGCDTimerWithName:@"MusicPlayerTimer" Interval:self.reportTime Queue:queue Repeats:YES Action:^{
  581. MusicTimeStamp currentStamp;
  582. CheckError(MusicPlayerGetTime(weakSelf.musicPlayer, &currentStamp), "MusicPlayerGetTime_CurrentTimeStamp");
  583. double currentPlayTime;
  584. CheckError(MusicSequenceGetSecondsForBeats(weakSelf.musicSequence, currentStamp, &currentPlayTime), "MusicSequencself->GetSecondsForBeats_CurrentTime");
  585. weakSelf.currentTime = currentPlayTime;
  586. if (weakSelf.currentTime >= weakSelf.totalTime) {
  587. weakSelf.currentTime = weakSelf.totalTime;
  588. dispatch_async(dispatch_get_main_queue(), ^{
  589. if ([weakSelf.delegate respondsToSelector:@selector(playEnd)]) {
  590. [weakSelf.delegate playEnd];
  591. }
  592. // 进度上报100%
  593. if([weakSelf.delegate respondsToSelector:@selector(ProgressUpdated:currentTime:)]) {
  594. [weakSelf.delegate ProgressUpdated:weakSelf.currentTime/weakSelf.totalTime currentTime:weakSelf.currentTime];
  595. }
  596. });
  597. [[GCDTimer shared] cancelAllTimer];
  598. CheckError(MusicPlayerStop(weakSelf.musicPlayer), "MusicPlayerStop");
  599. weakSelf.playing = NO;
  600. weakSelf.currentTime = 0;
  601. CheckError(MusicSequenceGetBeatsForSeconds(weakSelf.musicSequence, weakSelf.currentTime, &currentStamp), "MusicSequenceGetBeatsForSeconds_SetCurrentStamp");
  602. CheckError(MusicPlayerSetTime(weakSelf.musicPlayer, currentStamp), "MusicPlayerSetTime_SetZero");
  603. }
  604. else {
  605. // 如果是选段播放 到结束
  606. if (weakSelf.endTime != 0 && weakSelf.currentTime >= weakSelf.endTime) {
  607. dispatch_async(dispatch_get_main_queue(), ^{
  608. if ([weakSelf.delegate respondsToSelector:@selector(playEnd)]) {
  609. [weakSelf.delegate playEnd];
  610. }
  611. });
  612. [[GCDTimer shared] cancelAllTimer];
  613. CheckError(MusicPlayerStop(weakSelf.musicPlayer), "MusicPlayerStop");
  614. weakSelf.playing = NO;
  615. weakSelf.currentTime = 0;
  616. CheckError(MusicSequenceGetBeatsForSeconds(weakSelf.musicSequence, weakSelf.currentTime, &currentStamp), "MusicSequenceGetBeatsForSeconds_SetCurrentStamp");
  617. CheckError(MusicPlayerSetTime(weakSelf.musicPlayer, currentStamp), "MusicPlayerSetTime_SetZero");
  618. }
  619. else {
  620. dispatch_async(dispatch_get_main_queue(), ^{
  621. if ([weakSelf.delegate respondsToSelector:@selector(ProgressUpdated:currentTime:)]){
  622. [weakSelf.delegate ProgressUpdated:weakSelf.currentTime/weakSelf.totalTime currentTime:weakSelf.currentTime];
  623. }
  624. });
  625. }
  626. }
  627. }];
  628. }
  629. - (void)stopPlayingMIDIFile {
  630. CheckError(MusicPlayerStop(self.musicPlayer), "MusicPlayerStop");
  631. self.playing = NO;
  632. [[GCDTimer shared] cancelAllTimer];
  633. }
  634. - (BOOL)setMusicPlayerSpeed:(double)speed {
  635. if(speed<0) return NO;
  636. else {
  637. self.timeRatio = speed;
  638. if (self.musicPlayer){
  639. CheckError(MusicPlayerSetPlayRateScalar(self.musicPlayer, self.timeRatio), "MusicPlayerSetPlayRateScalar");
  640. }
  641. return YES;
  642. }
  643. }
  644. - (void)setProgress:(double)progress {
  645. if(progress>1||progress<0) return;
  646. self.currentTime = self.totalTime * progress;
  647. MusicTimeStamp currentStamp;
  648. CheckError(MusicSequenceGetBeatsForSeconds(self.musicSequence, self.currentTime, &currentStamp), "MusicSequenceGetBeatsForSeconds_SetCurrentStamp");
  649. CheckError(MusicPlayerSetTime(self.musicPlayer, currentStamp), "MusicPlayerSetTime_SetZero");
  650. // [self stopPlayingMIDIFile];
  651. }
  652. - (void)setProgressTime:(MusicTimeStamp)startTime {
  653. if (startTime < 0 || startTime > self.totalTime) {
  654. return;
  655. }
  656. self.currentTime = startTime;
  657. MusicTimeStamp currentStamp;
  658. CheckError(MusicSequenceGetBeatsForSeconds(self.musicSequence, self.currentTime, &currentStamp), "MusicSequenceGetBeatsForSeconds_SetCurrentStamp");
  659. CheckError(MusicPlayerSetTime(self.musicPlayer, currentStamp), "MusicPlayerSetTime_SetZero");
  660. // [self stopPlayingMIDIFile];
  661. }
  662. - (void)muteWithInstrument:(UInt8)instrument {
  663. if(instrument<0||instrument>127) return;
  664. NSNumber* numIns = [NSNumber numberWithInt:instrument];
  665. [self.instrumentArray addObject:numIns];
  666. self.isMute = YES;
  667. }
  668. -(void)muteWithDrum {
  669. self.muteDrum = YES;
  670. }
  671. -(BOOL)isPlayingFile {
  672. return self.playing;
  673. }
  674. -(double)musicTotalTime {
  675. return self.totalTime;
  676. }
  677. -(double)musicCurrentTime {
  678. return self.currentTime;
  679. }
  680. - (void)volume:(float)volume WithTrack:(UInt32)trackNum {
  681. if(volume<0||volume>1) return;
  682. if(trackNum<0||trackNum>self.trackCount) return;
  683. CheckError(AudioUnitSetParameter(_mixerUnit,
  684. kMultiChannelMixerParam_Volume,
  685. kAudioUnitScope_Input,
  686. trackNum,
  687. volume,
  688. 0),
  689. "AudioUnitSetMixerInputVolume");
  690. }
  691. /* 调整除了 trackNum 之外的 其他轨道的音量 范围[0,1]*/
  692. - (void)volumeOtherTrackExcept:(UInt32)trackNum withVolume:(float)volume {
  693. if(volume<0||volume>1) return;
  694. if(trackNum<0||trackNum>self.trackCount) return;
  695. CheckError(AudioUnitSetParameter(_mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Input, trackNum, 1, 0), "AudioUnitSetMixerInputVolume");
  696. }
  697. - (void)getAllTrackVolume {
  698. for (int i = 0; i < self.trackCount; i++) {
  699. float volume = 0.0f;
  700. AudioUnitGetParameter(_mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Input, i, &volume);
  701. NSLog(@"------ track %d --- volume :%.2f", i, volume);
  702. }
  703. }
  704. - (void)muteTrack:(BOOL)isMute WithTrack:(NSMutableArray *)trackArray {
  705. Boolean mutedBoolean = isMute ? TRUE : FALSE;
  706. for (NSNumber *trackNo in trackArray) {
  707. MusicTrack track;
  708. MusicSequenceGetIndTrack(self.musicSequence, trackNo.intValue, &track);
  709. MusicTrackSetProperty(track, kSequenceTrackProperty_MuteStatus, &mutedBoolean, sizeof(mutedBoolean));
  710. }
  711. }
  712. - (void)cleanup {
  713. if (self.musicPlayer) {
  714. //当前在播放,先暂停
  715. if ([self isPlayingFile]) {
  716. [self stopPlayingMIDIFile];
  717. }
  718. CheckError(MusicSequenceGetTrackCount(self.musicSequence, &_trackCount), "MusicSequenceGetTrackCount");
  719. MusicTrack track;
  720. for (int i = 0;i < self.trackCount; i++) {
  721. CheckError(MusicSequenceGetIndTrack (self.musicSequence,0,&track), "MusicSequenceGetIndTrack");
  722. CheckError(MusicSequenceDisposeTrack(self.musicSequence, track), "MusicSequenceDisposeTrack");
  723. }
  724. CheckError(DisposeMusicPlayer(self.musicPlayer), "DisposeMusicPlayer");
  725. CheckError(DisposeMusicSequence(self.musicSequence), "DisposeMusicSequence");
  726. CheckError(DisposeAUGraph(self.processingGraph), "DisposeAUGraph");
  727. self.playing=NO;
  728. [self.samplerNodeList removeAllObjects];
  729. [self.samplerUnitList removeAllObjects];
  730. [self.instrumentArray removeAllObjects];
  731. [self.instrumentTrackNameArray removeAllObjects];
  732. self.isMute = NO;
  733. self.muteDrum = NO;
  734. NSLog(@"CleanUp!");
  735. }
  736. }
  737. #pragma mark ------ 变调 调整hz
  738. - (void)transformTo442Hz {
  739. [self adjustPitchByHZ:442.0f];
  740. }
  741. // hz调整 440 - 442。。。。。。。
  742. - (void)adjustPitchByHZ:(float)newHZ {
  743. // 415 ~ 466
  744. if (newHZ < 415 || newHZ > 466) {
  745. return;
  746. }
  747. /**
  748. 1200音分等于一个八度音程,频率比为2:1,等程半音(相当于相邻钢琴键间的音程)等于100音分。这意味着1音分正好等于21/1200,即
  749. 如果知道两个音a和b的频率,两个音相距的音分值n可用下列公式计算(类似分贝定义式的形式,目的是为了使指数形式的物理单位线性化,使其化为对数):
  750. n=1200 *log2(a/b) == 3986 *log10(a/b)
  751. */
  752. Float32 censt = log2(newHZ/440.0) * 1200;
  753. AudioUnitSetParameter(self.pitchUnit, kNewTimePitchParam_Pitch, kAudioUnitScope_Global, 0, censt, 0);
  754. }
  755. #pragma mark ---- 自动循环功能和播放时同步节拍器暂未实现
  756. - (void)startPlaybackLoop {
  757. self.isLooping = YES;
  758. [self startPlaybackFromPosition:0];
  759. }
  760. - (void)startPlaybackFromPosition:(MusicTimeStamp)position {
  761. if (self.playing) {
  762. [self stopPlayback];
  763. }
  764. [self loopTrackWhenNeed];
  765. [self addClickTrackWhenNeededFromTimeStamp:position];
  766. // CheckError(<#OSStatus error#>, <#const char *operation#>)
  767. }
  768. #pragma mark ---- Looping
  769. - (void)loopTrackWhenNeed {
  770. if (self.isLooping) {
  771. MusicTrackLoopInfo loopInfo;
  772. loopInfo.numberOfLoops = 0;
  773. loopInfo.loopDuration = self.trackLength;
  774. MusicTrack track;
  775. // 设置循环播放属性
  776. for (int i = 0; i < self.trackCount; i++) {
  777. CheckError(MusicSequenceGetIndTrack (self.musicSequence, i, &track), "MusicSequenceGetIndTrack");
  778. CheckError(MusicTrackSetProperty(track, kSequenceTrackProperty_LoopInfo, &loopInfo, sizeof(loopInfo)), "MusicTrackSetProperty loop");
  779. }
  780. }
  781. }
  782. #pragma mark ----- click tracks
  783. - (void)addClickTrackWhenNeededFromTimeStamp:(MusicTimeStamp)fromTimeStamp {
  784. if (self.isClickPlayer) {
  785. return;
  786. }
  787. if (self.isClickTrackEnabled == NO) {
  788. return;
  789. }
  790. self.clickPlayer = [[MidiPlayerEngine alloc] init];
  791. self.clickPlayer->_isClickPlayer = YES;
  792. // 添加节拍器mid声轨
  793. }
  794. #pragma mark --- Properties
  795. - (void)setIsLooping:(BOOL)isLooping {
  796. if (isLooping != _isLooping) {
  797. _isLooping = isLooping;
  798. if (self.playing) { // 如果正在播放 停止之后从新开启播放
  799. }
  800. }
  801. }
  802. #pragma mark --- Lazyload
  803. - (NSMutableArray*)samplerNodeList {
  804. if (!_samplerNodeList) {
  805. _samplerNodeList = [[NSMutableArray alloc] init];
  806. }
  807. return _samplerNodeList;
  808. }
  809. - (NSMutableArray*)samplerUnitList {
  810. if (!_samplerUnitList) {
  811. _samplerUnitList = [[NSMutableArray alloc] init];
  812. }
  813. return _samplerUnitList;
  814. }
  815. -(NSMutableArray*)instrumentArray {
  816. if (!_instrumentArray) {
  817. _instrumentArray = [[NSMutableArray alloc] init];
  818. }
  819. return _instrumentArray;
  820. }
  821. - (NSMutableArray *)muteTrackArray {
  822. if (!_muteTrackArray) {
  823. _muteTrackArray = [NSMutableArray array];
  824. }
  825. return _muteTrackArray;
  826. }
  827. - (NSMutableDictionary *)instrumentTrackParm {
  828. if (!_instrumentTrackParm) {
  829. _instrumentTrackParm = [NSMutableDictionary dictionary];
  830. }
  831. return _instrumentTrackParm;
  832. }
  833. - (void)dealloc {
  834. NSLog(@"************ player engine dealloc!");
  835. }
  836. /*
  837. 物理连接
  838. ____________
  839. | |
  840. | Sampler |-------
  841. | | |
  842. ------------ |
  843. |
  844. ____________ | ---------------------- ------------
  845. | | ----->| | | |
  846. | Sampler |------------->| MultiChannel Mixer |------------->| I/O |
  847. | | ----->| | | |
  848. ------------ | ---------------------- ------------
  849. |
  850. ____________ |
  851. | | |
  852. | Sampler |-------
  853. | |
  854. ------------
  855. --------------------- -------------------------------------------------
  856. | MusicSequence | | AUGraph |
  857. | | | |
  858. | MusicTrack1 ---|--------| ->MIDISynth1 |
  859. | | | --->MixerNode -------> OutputNode|
  860. | MusicTrack2 ---|--------| ->MIDISynth2 |
  861. | | | |
  862. --------------------- -------------------------------------------------
  863. */
  864. @end