2012-03-19 7 views
0

私は、MIDIイベントの再生中にユーザーイベントが渡されたときに呼び出されるユーザーイベントコールバックの内容に基づいて、UI要素(UIImageViews)の更新方法を理解しようとしています。より具体的には、これらのユーザイベントは、ユーザコールバック機能に渡されるノートデータ(例えば、演奏されたノートは60、ミドルC)を含む。ユーザーコールバックとビューの間の会話方法

再生するノートに基づいてUIImageViewsを更新したいと思います。コールバック内からUIImageViewsにアクセスしようとしましたが、ViewControllerに直接アクセスすることができず、メインのスレッド以外のスレッドで実行されるため、別の方法で行うことをお勧めしています。

私がしたいのは、コールバック関数からUIに情報を中継することができる別のコントローラを作成することですが、それを行うには誰に分かりません。私は下の私のViewControllerのコードを掲載しました。これには、コールバック関数と、ユーザーイベントやその他のビュー関連の設定用の関連コードが含まれています。

私はXcode 4.3.1とiOS 5で作業していますが、ARCを使用しています。

PracticeViewController.h

#import <UIKit/UIKit.h> 
#import "Lesson.h" 
#import "Note.h" 
#import <AudioToolbox/AudioToolbox.h> 

@interface PracticeViewController : UIViewController 

@property (strong, nonatomic) Lesson *selectedLesson; 
@property (strong, nonatomic) IBOutlet UINavigationItem *practiceWindowTitle; 
@property MusicPlayer player; 

//Outlets for White Keys 
@property (strong, nonatomic) IBOutlet UIImageView *whiteKey21; 
// […] 
@property (strong, nonatomic) IBOutlet UIImageView *whiteKey108; 

//Outlets for Black Keys 
@property (strong, nonatomic) IBOutlet UIImageView *blackKey22; 
// […] 
@property (strong, nonatomic) IBOutlet UIImageView *blackKey106; 

// Key Highlight Images 
@property (strong, nonatomic) UIImage *highlightA; 
@property (strong, nonatomic) UIImage *highlightB; 
@property (strong, nonatomic) UIImage *highlightC; 
@property (strong, nonatomic) UIImage *highlightD; 
@property (strong, nonatomic) UIImage *highlightE; 
@property (strong, nonatomic) UIImage *highlightF; 
@property (strong, nonatomic) UIImage *highlightG; 
@property (strong, nonatomic) UIImage *highlightH; 

- (IBAction)practiceLesson:(id)sender; 

@end 

PracticeViewController.m

#import "PracticeViewController.h" 

@interface PracticeViewController() 

@end 

@implementation PracticeViewController 
@synthesize blackKey22; 
// […] 
@synthesize blackKey106; 
@synthesize whiteKey21; 
// […] 
@synthesize whiteKey108; 

@synthesize selectedLesson, practiceWindowTitle, player, highlightA, highlightB, highlightC, highlightD, highlightE, highlightF, highlightG, highlightH; 

// Implement the UserEvent structure. 

typedef struct UserEvent { 
    UInt32 length; 
    UInt32 typeID; 
    UInt32 trackID; 
    MusicTimeStamp tStamp; 
    MusicTimeStamp dur; 
    int playedNote; 
} UserEvent; 

// Implement the UserCallback function. 

void noteUserCallback (void *inClientData, MusicSequence inSequence, MusicTrack inTrack, MusicTimeStamp inEventTime, const MusicEventUserData *inEventData, MusicTimeStamp inStartSliceBeat, MusicTimeStamp inEndSliceBeat) 
{  
    UserEvent* event = (UserEvent *)inEventData; 
    UInt32 size = event->length; 
    UInt32 note = event->playedNote; 
    UInt32 timestamp = event->tStamp; 
    NSLog(@"Size: %lu Note: %lu, Timestamp: %lu", size, note, timestamp); 
} 

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 
    if (self) { 
     // Custom initialization 
    } 

    return self; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    self.practiceWindowTitle.title = selectedLesson.titleAndSubtitle; 

    // Load in the images for the glow. 
    highlightA = [UIImage imageNamed:@"glow_whiteKeysA.png"]; 
    highlightB = [UIImage imageNamed:@"glow_whiteKeysB.png"]; 
    highlightC = [UIImage imageNamed:@"glow_whiteKeysC.png"]; 
    highlightD = [UIImage imageNamed:@"glow_whiteKeysD.png"]; 
    highlightE = [UIImage imageNamed:@"glow_whiteKeysE.png"]; 
    highlightF = [UIImage imageNamed:@"glow_whiteKeysF.png"]; 
    highlightG = [UIImage imageNamed:@"glow_blackKey.png"]; 
    highlightH = [UIImage imageNamed:@"glow_whiteKeysH.png"]; 

    // Create player, sequence, left/right hand tracks, and iterator. 

    NewMusicPlayer(&player); 
    MusicSequence sequence; 
    NewMusicSequence(&sequence); 
    MusicTrack rightHand; 
    MusicTrack leftHand; 
    MusicEventIterator iterator; 

    // Load in MIDI file. 

    NSString *path = [[NSString alloc] init]; 
    path = [[NSBundle mainBundle] pathForResource:selectedLesson.midiFilename ofType:@"mid"]; 
    NSURL *url = [NSURL fileURLWithPath:path]; 
    MusicSequenceFileLoad(sequence, (__bridge CFURLRef)url, 0, kMusicSequenceLoadSMF_ChannelsToTracks); 

    // Get the right and left hand tracks from the sequence. 

    int rightHandIndex = 0; 
    //int leftHandIndex = 1; 

    MusicSequenceGetIndTrack(sequence, rightHandIndex, &rightHand); //Get right hand. 
    //MusicSequenceGetIndTrack(sequence, leftHandIndex, leftHand); //Get left hand. 

    //Iterate through the right hand track and add user events. 

    Boolean hasNextEvent = false; 
    Boolean hasEvent = false; 

    NewMusicEventIterator(rightHand, &iterator); 
    MusicEventIteratorHasCurrentEvent(iterator, &hasEvent); 
    MusicEventIteratorHasNextEvent(iterator, &hasNextEvent); 

    while (hasNextEvent == true) { 
     MusicTimeStamp timestamp = 0; 
     MusicEventType eventType = 0; 
     const void *eventData = NULL; 
     int note; 
     MusicTimeStamp duration; 

     MusicEventIteratorGetEventInfo(iterator, &timestamp, &eventType, &eventData, NULL); 

     if (eventType == kMusicEventType_MIDINoteMessage) { 
      MIDINoteMessage *noteMessage = (MIDINoteMessage *)eventData; 
      note = noteMessage->note; 
      duration = noteMessage->duration; 
      UserEvent event; 

      event.length = 0; 
      event.length = sizeof(UserEvent); 
      event.playedNote = note; 
      event.tStamp = timestamp; 

      MusicEventUserData* data = (MusicEventUserData *)&event; 
      MusicTrackNewUserEvent(rightHand, timestamp, data); 
     } 

     MusicEventIteratorHasNextEvent(iterator, &hasNextEvent); 
     MusicEventIteratorNextEvent(iterator); 
    } 

    MusicSequenceSetUserCallback(sequence, noteUserCallback, NULL); 

    MusicPlayerSetSequence(player, sequence); 
    MusicPlayerPreroll(player); 
} 

- (void)viewDidUnload 
{ 
    [self setPracticeWindowTitle:nil]; 
    [self setWhiteKey21:nil]; 
    // […] 
    [self setWhiteKey108:nil]; 
    [self setBlackKey22:nil]; 
    // […] 
    [self setBlackKey106:nil]; 
    [super viewDidUnload]; 
    // Release any retained subviews of the main view. 
} 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
    return YES; 
} 

- (IBAction)practiceLesson:(id)sender { 
    MusicPlayerStart(player); 
} 
@end 
+0

うわー、それはたくさんのIBOutletsです。 – meggar

+0

5は、多くの 'IBOutlets'ですか? – msgambel

+0

単なる切り捨てです。 UIImageViewsには88のIBOutletsがあります。フルキーボードのすべてのキーに1つ。ところで、エミールに感謝:) – Barks

答えて

1

あなたはyour other questionで正しい軌道に乗っていました。なぜ私はあなたが全く異なるアプローチを必要としているのか分かりません。あなたのコールバックで

dispatch_get_main_queue-performSelectorOnMainThread:またはdispatch_asyncを使用して、メインスレッド上でUIを触れるどんな仕事をしてください。おそらく、PracticeViewControllerを使用するコードはメインスレッド上になければなりません。

void noteUserCallback (void *inClientData, MusicSequence inSequence, MusicTrack inTrack, MusicTimeStamp inEventTime, const MusicEventUserData *inEventData, MusicTimeStamp inStartSliceBeat, MusicTimeStamp inEndSliceBeat) 
{ 
    PracticeViewController* pvc = (__bridge PracticeViewController *)inClientData; 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     [pvc.whiteKey21 setImage:pvc.highlightA]; 
    }); 
    ... 
} 
+0

まあ、私は気になるでしょう。私はもうちょっと立ち止まっていなければならないと思う。そんなことをやっているのはあまりにも厄介だと思った友人がいます。スレッドを切り替えることはトリックでした! :)ありがとうKurt。ほんとうにありがとう。私は数日間このことに固執してきました。好奇心から、別のスレッドからUIを更新できないのはなぜですか? – Barks

+0

短い答えは「それはAppKitとUIKitのしくみです」これはエンジニアリングの妥協点です。 UIはシーケンシャルに動作する必要があります。入力を繰り返し受け取り、ハンドラに送り、画面を再描画するため、最も自然な方法は1つのスレッドで順番に実行することです。そのプロセスの途中で別のスレッドがUIデータを変更した場合、UIスレッドはその変更を処理する用意ができません。あなたは、UIKitが自動的にそれを処理すべきだと主張することができますが、これは実行するよりはるかに簡単です。特に非常に制約のあるデバイスではパフォーマンスを高く保ちます。 –

関連する問題