void SeqPhraseMatrixView::ShowProperties(BPoint where) { track_id trackId = TrackId(where); AmPhraseEvent* pe = NULL; SeqSongWinPropertiesI* win = dynamic_cast<SeqSongWinPropertiesI*>(Window() ); _SeqPhraseToolTarget* target; if (win && trackId && (target = new _SeqPhraseToolTarget(win, this, &mMtc)) ) { // READ SONG BLOCK #ifdef AM_TRACE_LOCKS printf("SeqPhraseMatrixView::ShowProperties() read lock\n"); fflush(stdout); #endif const AmSong* song = mSongRef.ReadLock(); if (song) { const AmTrack* track = song->Track(trackId); if (track) { pe = target->PhraseEventAt(track, where); if (pe) pe->IncRefs(); } } mSongRef.ReadUnlock(song); // END READ SONG BLOCK delete target; } /* Done this way so I get out of the read lock as soon as * possible (and because opening the properties window causes * a read lock, and I don't want them nested). */ if (pe) { ShowPropertiesWin(pe); pe->DecRefs(); } }
void AmTrackDataView::DrawPhrase( BRect clip, BView* view, track_id trackId, const AmPhraseEvent& topPhrase, AmPhraseEvent* pe, AmTime start, AmTime end, int32 properties, AmSelectionsI* selections) { ArpASSERT(pe && pe->Phrase()); AmNode* n = pe->Phrase()->HeadNode(); if (!n) return; AmRange eventRange = topPhrase.EventRange( n->Event() ); while (n && eventRange.start <= end) { if (eventRange.end >= start) { if (mTarget->IsInteresting( n->Event() )) { if (selections && selections->IncludesEvent(trackId, &topPhrase, n->Event() ) ) DrawEvent(view, topPhrase, n->Event(), eventRange, ARPEVENT_SELECTED); else DrawEvent(view, topPhrase, n->Event(), eventRange, properties); } else if (n->Event()->Type() == n->Event()->PHRASE_TYPE) { AmPhraseEvent* pe2 = dynamic_cast<AmPhraseEvent*>( n->Event() ); if (pe2) DrawPhrase(clip, view, trackId, topPhrase, pe2, start, end, properties, selections); } } n = n->next; if (n) eventRange = topPhrase.EventRange( n->Event() ); } }
/* This method finds the first event that STARTS after my left edge. * events that are overhanging into my left border are ignored. This * is an arbitrary decision, but basically it makes sense to me to do * it this way because this method is used to select the first visible * event, if there isn't already one. And if I did it the other way, * then that overhanging note might actually be measures away, so as users * clicked the right arrow the actual events being selected would be far * away. */ AmEvent* AmTrackDataView::FirstEvent(const AmTrack* track, AmPhraseEvent** answer) const { ArpASSERT(mTarget); const AmPhrase& phrase = track->Phrases(); AmTime time = mTarget->TimeConverter().PixelToTick( Bounds().left ); AmNode* phraseNode = phrase.FindNode( time, BACKWARDS_SEARCH ); if( !phraseNode ) return 0; AmPhraseEvent* pe; while (phraseNode != 0) { if( (phraseNode->Event()->Type() == phraseNode->Event()->PHRASE_TYPE) && (pe = dynamic_cast<AmPhraseEvent*>( phraseNode->Event() )) && pe->Phrase() ) { AmNode* eventNode = pe->Phrase()->FindNode( time, FORWARDS_SEARCH ); while( eventNode ) { if( mTarget->IsInteresting( eventNode->Event() ) ) { *answer = pe; return eventNode->Event(); } eventNode = eventNode->next; } } phraseNode = phraseNode->next; } return 0; }
void AmTrackDataView::SelectRightEvent() { #if 0 ArpASSERT(mTarget); AmSelectionsI* newSelections = NULL; // READ SONG BLOCK #ifdef AM_TRACE_LOCKS printf("AmTrackDataView::SelectRightEvent() read lock\n"); fflush(stdout); #endif const AmSong* song = mSongRef.ReadLock(); const AmTrack* track = song ? song->Track(mTrackWinProps.OrderedTrackAt(0)) : NULL; if (track) { AmSelectionsI* selections = mTrackWinProps.Selections(); /* If there are no selections, select the first event * starting on or after the left edge of the window. */ if (!selections || selections->CountEvents() < 1) { newSelections = SelectFirstEvent(track); /* If there are already events, select the next event * over from the end of the last selected event. And if * that event isn't visible, select the first visible event. */ } else { /* Find the event to move right from. */ AmEvent* event = 0; AmPhraseEvent* container = 0; AmEvent* iteratingEvent; AmPhraseEvent* iteratingContainer; for (uint32 k = 0; selections->EventAt(k, &iteratingContainer, &iteratingEvent) == B_OK; k++) { if (!event || (iteratingContainer->EventRange(iteratingEvent).start > container->EventRange(event).start) ) { event = iteratingEvent; container = iteratingContainer; } } if (!event) newSelections = SelectFirstEvent(track); else { /* Select the next event over. This has a lot of problems, * like not dealing with operlapping phrases. */ if (NextRightEvent(track, event, container, &iteratingEvent, &iteratingContainer) == B_OK) newSelections = SelectEvent(iteratingEvent, iteratingContainer); else newSelections = SelectFirstEvent(track); } } } mSongRef.ReadUnlock(song); // END READ SONG BLOCK if (newSelections) mTrackWinProps.SetSelections(newSelections); #endif }
static void control_report(const AmPhrase* phrase, _AmControlEntry& entry) { if (!phrase) return; AmNode* node = phrase->HeadNode(); while (node) { if (node->Event() ) { if (node->Event()->Type() == node->Event()->PHRASE_TYPE) { AmPhraseEvent* pe = dynamic_cast<AmPhraseEvent*>(node->Event() ); if (pe) control_report(pe->Phrase(), entry); } else if (node->Event()->Type() == node->Event()->CONTROLCHANGE_TYPE) { AmControlChange* cc = dynamic_cast<AmControlChange*>(node->Event() ); if (cc) entry.AddControl(cc->ControlNumber() ); } } node = node->next; } }
static void program_report(const AmPhrase* phrase, _AmProgramEntry& entry) { if (!phrase) return; AmNode* node = phrase->HeadNode(); while (node) { if ( node->Event() ) { if (node->Event()->Type() == node->Event()->PHRASE_TYPE) { AmPhraseEvent* pe = dynamic_cast<AmPhraseEvent*>( node->Event() ); if (pe) program_report(pe->Phrase(), entry); } else if (node->Event()->Type() == node->Event()->PROGRAMCHANGE_TYPE) { AmProgramChange* pc = dynamic_cast<AmProgramChange*>( node->Event() ); if (pc) entry.AddProgram( pc->ProgramNumber() ); } } node = node->next; } }
static void _control_report(const AmPhrase* phrase, uint8* active) { if (!phrase) return; AmNode* node = phrase->HeadNode(); while (node) { if (node->Event() ) { if (node->Event()->Type() == node->Event()->PHRASE_TYPE) { AmPhraseEvent* pe = dynamic_cast<AmPhraseEvent*>(node->Event() ); if (pe) _control_report(pe->Phrase(), active); } else if (node->Event()->Type() == node->Event()->CONTROLCHANGE_TYPE) { AmControlChange* cc = dynamic_cast<AmControlChange*>(node->Event() ); if (cc) active[cc->ControlNumber()] = 1; } } node = node->next; } }
void _AmControlTarget::GetMoveValues( const AmPhraseEvent& topPhrase, const AmEvent* event, AmTime* x, int32* y) const { ArpASSERT(event); *x = topPhrase.EventRange(event).start; const AmControlChange* ccEvent = dynamic_cast<const AmControlChange*>(event); if (ccEvent) *y = ccEvent->ControlValue(); else *y = 0; }
void AmTrackDataView::DrawTrack(const AmTrack* track, BRect clip, BView* view, int32 properties, AmSelectionsI* selections) { AmTime start = mMtc.PixelToTick(clip.left - 2); AmTime end = mMtc.PixelToTick(clip.right + 2); AmNode* n = track->Phrases().HeadNode(); while (n && n->Event() && n->StartTime() <= end) { if (n->EndTime() >= start) { if (n->Event()->Type() == n->Event()->PHRASE_TYPE) { AmPhraseEvent* pe = dynamic_cast<AmPhraseEvent*>( n->Event() ); if (pe && pe->Phrase() ) { mEventColor = pe->Phrase()->Color(AmPhrase::FOREGROUND_C); mix_in(mEventColor, AmPrefs().Color(AM_DATA_BG_C), 0.75, mLowEventColor); DrawPhrase(clip, view, track->Id(), *pe, pe, start, end, properties, selections); } } } n = n->next; } }
void _AmControlTarget::SetMove( AmPhraseEvent& topPhrase, AmEvent* event, AmTime originalX, int32 originalY, AmTime deltaX, int32 deltaY, uint32 flags) { ArpASSERT(event); AmControlChange* ccEvent = dynamic_cast<AmControlChange*>(event); if (!ccEvent) return; // if (flags&TRANSFORM_X) { AmTime newStart = originalX + deltaX; if (newStart < 0) newStart = 0; if (newStart != topPhrase.EventRange(event).start) topPhrase.SetEventStartTime(ccEvent, newStart); // if (flags&TRANSFORM_Y) { int32 newVal = originalY + deltaY; if (newVal > 127) newVal = 127; else if (newVal < 0) newVal = 0; ccEvent->SetControlValue(newVal); // } }