我是Objective C的新手,我正在尝试创建一个应用程序,当按下按钮时,该应用程序将播放midi文件。我还希望它在播放文件时不响应其他按钮按下。我创建了一个自定义按钮类,并将此代码(来自教程)放入.m文件中:
- (IBAction)MIDItest:(id)sender
{
MusicSequence s;
NewMusicSequence(&s);
NSString *midiFilePath = [[NSBundle mainBundle]
pathForResource:@"eDom"
ofType:@"mid"];
NSURL *midiFileURL = [NSURL fileURLWithPath:midiFilePath];
MusicSequenceFileLoad(s, (__bridge CFURLRef)(midiFileURL), 0, 0);
MusicPlayer p;
NewMusicPlayer(&p);
MusicPlayerSetSequence(p, s);
MusicPlayerPreroll(p);
MusicPlayerStart(p);
MusicTrack t;
MusicTimeStamp len;
UInt32 sz = sizeof(MusicTimeStamp);
MusicSequenceGetIndTrack(s, 1, &t);
MusicTrackGetProperty(t, kSequenceTrackProperty_TrackLength, &len, &sz);
while (1) {
usleep (3 *1000 *1000);
MusicTimeStamp now = 0;
MusicPlayerGetTime(p, &now);
if (now >= len)
break;
}
MusicPlayerStop(p);
DisposeMusicSequence(s);
DisposeMusicPlayer(p);
}
然而,当我按下按钮时,没有任何反应。我确实将按钮设置为自定义类,所以我认为问题出在midi播放器代码中。谁能告诉我我做错了什么以及如何解决这个问题?
答案 0 :(得分:1)
该代码存在许多问题。使用while (1)
和usleep
作为控制结构是一个非常糟糕的主意。它会在midi文件的持续时间内锁定用户界面。我的猜测是,这只是一些糟糕的教程代码,旨在展示如何使用MusicPlayer API,但无意中显示了一种非常糟糕的实现方式。
正确的方法是将MusicPlayer声明为@property,以便它在应用程序的生命周期内持续存在(或者需要很长时间),并根据需要设置和删除MusicSequences。
您的代码的具体问题是MusicTracks是基于零的(下面的标题定义),并且您要求轨道1,我猜测它不存在。返回错误但您没有检查它。所有MusicPlayer函数都返回一个结果代码,你应该总是检查它们(或者在调试地狱中盲目地......; - )
你检查这样的错误:
OSStatus result = noErr;
result = MusicSequenceGetIndTrack(s, 1, &t);
if (result) {[self printErrorMessage: @"MusicSequenceGetIndTrack" withStatus: result];}
printErrorMessage
函数(包含在下面)只是为了方便记录字符串和结果代码。
至于为什么你的代码不工作:如果轨道不存在,它的长度将为零,因此你的睡眠代码不起作用,方法将立即退出。您可以通过以下方式查看:
printf(" len %f\n", len);
MusicPlayer API非常强大且使用起来很有趣,但始终会检查错误结果代码(listed here),因为它会无声地失败,如果没有它们,您将无法获得线索。
- (void) printErrorMessage: (NSString *) errorString withStatus: (OSStatus) result
{
char str[20];
// see if it appears to be a 4-char-code
*(UInt32 *)(str + 1) = CFSwapInt32HostToBig(result);
if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
str[0] = str[5] = '\'';
str[6] = '\0';
} else
// no, format it as an integer
sprintf(str, "%d", (int)result);
// fprintf(stderr, "Error: %s (%s)\n", operation, str);
NSLog (
@"*** %@ error: %s\n",
errorString,
str
);
}
/*!
@function MusicSequenceGetIndTrack
@abstract Get a track at the specified index
@discussion Index is zero based. It will return kAudio_ParamError if index is not in the range: 0 < TrackCount
The track count and accessors exclude the tempo track (which is treated as a special case)
@param inSequence the sequence
@param inTrackIndex the index
@param outTrack the track at that index
*/