void AmNode::CopyContentsTo(AmNode* copy) const { assert( copy ); if( !copy || !mEvent ) return; AmNode* node = copy; node->SetEvent( mEvent->Copy() ); }
void SeqPhraseMatrixView::DrawTrack(BRect clip, BView* view, const AmTrack* track, AmPhraseRendererI* renderer) { /* Find the first phrase left of the window. */ const AmPhrase& phrases = track->Phrases(); AmTime start = mMtc.PixelToTick(clip.left); AmTime end = mMtc.PixelToTick(clip.right); AmNode* n = phrases.FindNode(start, BACKWARDS_SEARCH); if (!n) n = phrases.FindNode(start); if (!n) return; while (n && (n->Event()->StartTime() <= end) ) { if( n->Event()->Type() == n->Event()->PHRASE_TYPE ) { AmPhraseEvent* pe = dynamic_cast<AmPhraseEvent*>( n->Event() ); if (pe) DrawTopLevelPhrase(clip, view, track, pe, end, pe, renderer); /* Events need to know if they are in a link or not, so they * are required to be bundled up in a phrase. */ } else { debugger("Error condition"); // } else if( n->Event()->Type() == n->Event()->NOTEON_TYPE ) { // DrawEvent( clip, view, dynamic_cast<AmNoteOn*>( n->Event() ) ); } n = n->next; } }
AmNode* AmNode::Copy() const { const AmNode* pos = this; AmNode* head = NULL; AmNode* tail = NULL; while (pos) { AmNode* copy = new AmNode(0); if (!copy) { if (head) { head->DeleteListContents(); delete head; } return NULL; } pos->CopyContentsTo( copy ); if (!tail) { head = tail = copy; } else { tail->InsertNext(copy); tail = copy; } pos = pos->next; } return head; }
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() ); } }
AmNode* AmNode::NodeBefore(AmTime time) { if( StartTime() >= time ) return 0; AmNode* pos = this; while (pos && pos->next && pos->StartTime() < time) pos = pos->next; return pos; }
void AmNode::DeleteListContents() { AmNode* pos = this; while (pos) { if( pos->mEvent ) { pos->pDeleteContents(); pos->mEvent = 0; } pos = pos->next; } }
const AmSignature* AmTimeView::GetSignatureBefore(const AmPhrase& signatures, int32 measure) { AmNode* node = signatures.HeadNode(); if( !node ) return 0; while ( (node != 0) && (node->next != 0) ) { const AmSignature* sig = dynamic_cast<const AmSignature*>( ((AmNode*)node->next)->Event() ); if ( (sig != 0) && (sig->Measure() > measure) ) return sig; node = (AmNode*)node->next; } return dynamic_cast<const AmSignature*>( node->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; }
status_t AmTimeView::ConstructSignatureFromTime(const AmPhrase& signatures) { debugger("This code doesn't work at all -- if anyone actually uses it, it needs to be rewritten"); AmNode* node = signatures.FindNode( DisplayTime(), BACKWARDS_SEARCH ); if( !node ) return B_ERROR; AmSignature* sig = dynamic_cast<AmSignature*>( node->Event() ); if( !sig ) return B_ERROR; AmTime start = sig->StartTime(); AmTime ticks = sig->TicksPerBeat(); AmTime displayTime = DisplayTime(); int32 measure = sig->Measure(); while ( (start + ticks) <= displayTime ) { start += ticks; measure++; } mSignature->Set( start, measure, sig->Beats(), sig->BeatValue() ); return B_OK; }
status_t AmTrackDataView::NextRightEvent( const AmTrack* track, AmEvent* event, AmPhraseEvent* container, AmEvent** eventAnswer, AmPhraseEvent** containerAnswer) const { #if 0 ArpASSERT( mTarget ); ArpASSERT( event && container && container->Phrase() ); AmNode* n = container->Phrase()->FindNode(event); // AmEvent* nextEvent = 0; /* Simple case, there's an event after the current one. */ if( n ) n = n->next; while( n ) { if( mTarget->IsInteresting( n->Event() ) ) { *eventAnswer = n->Event(); *containerAnswer = container; return B_OK; } n = n->next; } #endif return B_ERROR; }
AmTimeView::AmTimeView( const AmPhrase& signatures) : inherited(BRect(0, 0, 0, 0), "midi_time", B_FOLLOW_TOP | B_FOLLOW_LEFT, B_WILL_DRAW), AmSongObserver( AmSongRef() ), mSignature(new AmSignature), mTime(0), mMeasureCtrl(0), mBeatCtrl(0), mClockCtrl(0) { AmNode* n = signatures.HeadNode(); while( n ) { if( n->Event()->Type() == n->Event()->SIGNATURE_TYPE ) { AmSignature* event = dynamic_cast<AmSignature*>( n->Event() ); AmSignature* sig; if( event && (sig = new AmSignature( *event )) ) { mSignatures.Add( sig ); } } n = n->next; } AddViews(); }
AmEvent* _AmControlTarget::InterestingEventAt( const AmTrack* track, const AmPhraseEvent& topPhrase, const AmPhrase& phrase, AmTime time, float y, int32* extraData) const { AmNode* n = phrase.ChainHeadNode(time); if (!n) return NULL; /* Since control changes are single pixels, it can be a bit tricky * for users to hit exactly the right pixel. Compensate for this * by finding the closest control change within a given fudge factor. */ AmTime fudge = EventAtFudge(); AmEvent* closest = NULL; /* As soon as I've hit events that are within range of where I'm * looking, I set this flag. This lets me know to end the search * as soon as I'm out of range. */ bool beenInRange = false; while (n) { AmRange eventRange = topPhrase.EventRange( n->Event() ); if( (eventRange.start >= time - fudge) && (eventRange.start <= time + fudge) ) { beenInRange = true; if( IsInteresting( n->Event() ) ) { if (!closest) closest = n->Event(); else if ( abs(time - eventRange.start) < abs(time - topPhrase.EventRange(closest).start) ) closest = n->Event(); } } else { if (beenInRange) return closest; } n = n->next; } return closest; }
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; } }
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, _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; } }
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 SeqMeasureControl::LockedDrawRightOn( const AmPhrase& signatures, BRect rBounds, BView* view, AmTime songEndTime) { AmTime centerRightTime = mMtc.PixelToTick( rBounds.left - 1 - mLeftIndent + mScrollX ); if (centerRightTime < 0) return; AmTime timeWidth = songEndTime - centerRightTime; if( timeWidth < 0 ) return; AmTimeConverter mtc( mRightIndent / ((float)timeWidth / (float)PPQN) ); if( mtc.BeatLength() >= mMtc.BeatLength() ) return; AmNode* node = signatures.HeadNode(); if (node == 0) return; AmSignature* sig = dynamic_cast<AmSignature*>( node->Event() ); if (sig == 0) return; AmSignature currentSig(*sig); AmTime sigLength = currentSig.Duration(); AmSignature* nextSig = 0; AmNode* nextNode = node->next; if (nextNode != 0) nextSig = dynamic_cast<AmSignature*>( nextNode->Event() ); char buf[16]; float lastRight = -1; /* Find the first signature right of the center view. */ while (currentSig.EndTime() < centerRightTime) { currentSig.Set( currentSig.StartTime() + sigLength, currentSig.Measure() + 1, currentSig.Beats(), currentSig.BeatValue() ); if ( nextSig && ( currentSig.StartTime() == nextSig->StartTime() ) ) { int32 measure = currentSig.Measure(); currentSig.Set( *nextSig ); currentSig.SetMeasure( measure ); sigLength = currentSig.Duration(); node = nextNode; nextNode = (AmNode*)nextNode->next; if (nextNode != 0) nextSig = dynamic_cast<AmSignature*>( nextNode->Event() ); else nextSig = 0; } } DrawRightBgOn(rBounds, view, songEndTime); /* Draw the center dividing line. */ float fh = view_font_height(view); rBounds.top = rBounds.bottom - fh; view->SetHighColor( Prefs().Color( AM_MEASURE_FG_C ) ); view->StrokeLine( BPoint(rBounds.left, rBounds.top-1), BPoint(rBounds.right, rBounds.top-1) ); view->SetHighColor( Prefs().Color( AM_MEASURE_HIGHLIGHT_C ) ); view->StrokeLine( BPoint(rBounds.left, rBounds.top), BPoint(rBounds.right, rBounds.top) ); /* Now draw til the end. */ view->SetHighColor( Prefs().Color( AM_MEASURE_FG_C ) ); view->SetDrawingMode(B_OP_ALPHA); view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); while (currentSig.EndTime() < songEndTime) { float pixel = mtc.TickToPixel( currentSig.StartTime() - centerRightTime ); if( pixel > lastRight ) { view->StrokeLine( BPoint(pixel + rBounds.left, rBounds.top), BPoint(pixel + rBounds.left, rBounds.bottom) ); sprintf( buf, "%ld", currentSig.Measure() ); float width = view->StringWidth( buf ); view->DrawString( buf, BPoint( pixel + rBounds.left + 2, rBounds.bottom - 2 ) ); lastRight = pixel + 2 + width + 2; } currentSig.Set( currentSig.StartTime() + sigLength, currentSig.Measure() + 1, currentSig.Beats(), currentSig.BeatValue() ); if ( nextSig && ( currentSig.StartTime() == nextSig->StartTime() ) ) { int32 measure = currentSig.Measure(); currentSig.Set( *nextSig ); currentSig.SetMeasure( measure ); sigLength = currentSig.Duration(); node = nextNode; nextNode = (AmNode*)nextNode->next; if (nextNode != 0) nextSig = dynamic_cast<AmSignature*>( nextNode->Event() ); else nextSig = 0; } } view->SetDrawingMode(B_OP_COPY); }
void SeqMeasureControl::LockedDrawLeftOn(const AmPhrase& signatures, BRect lBounds, BView* view) { AmTime rightTick = mMtc.PixelToTick(mScrollX); AmTimeConverter mtc( mLeftIndent / ((float)rightTick / (float)PPQN) ); AmNode* node = signatures.HeadNode(); if (node == 0) return; AmSignature* sig = dynamic_cast<AmSignature*>( node->Event() ); if (sig == 0) return; AmSignature currentSig(*sig); AmTime sigLength = currentSig.Duration(); AmSignature* nextSig = 0; AmNode* nextNode = node->next; if (nextNode != 0) nextSig = dynamic_cast<AmSignature*>( nextNode->Event() ); char buf[16]; float lastRight = -1; /* Draw the center dividing line. */ float fh = view_font_height(view); lBounds.top = lBounds.bottom - fh; view->SetHighColor( Prefs().Color( AM_MEASURE_FG_C ) ); view->StrokeLine( BPoint(lBounds.left, lBounds.top-1), BPoint(lBounds.right, lBounds.top-1) ); view->SetHighColor( Prefs().Color( AM_MEASURE_HIGHLIGHT_C ) ); view->StrokeLine( BPoint(lBounds.left, lBounds.top), BPoint(lBounds.right, lBounds.top) ); view->SetHighColor( Prefs().Color( AM_MEASURE_FG_C ) ); view->SetDrawingMode(B_OP_ALPHA); view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); while (currentSig.EndTime() < rightTick) { float pixel = mtc.TickToPixel( currentSig.StartTime() ); if( pixel > lastRight ) { view->StrokeLine( BPoint(pixel, lBounds.top), BPoint(pixel, lBounds.bottom) ); sprintf( buf, "%ld", currentSig.Measure() ); float width = view->StringWidth( buf ); if( pixel + 2 + width > mLeftIndent ) { lastRight = pixel + 2; } else { view->DrawString( buf, BPoint( pixel + 2, lBounds.bottom - 2 ) ); lastRight = pixel + 2 + width + 2; } } currentSig.Set( currentSig.StartTime() + sigLength, currentSig.Measure() + 1, currentSig.Beats(), currentSig.BeatValue() ); if ( nextSig && ( currentSig.StartTime() == nextSig->StartTime() ) ) { int32 measure = currentSig.Measure(); currentSig.Set( *nextSig ); currentSig.SetMeasure( measure ); sigLength = currentSig.Duration(); node = nextNode; nextNode = (AmNode*)nextNode->next; if (nextNode != 0) nextSig = dynamic_cast<AmSignature*>( nextNode->Event() ); else nextSig = 0; } } view->SetDrawingMode(B_OP_COPY); }
status_t AmNode::AddNode(AmNode* node) { assert( node ); AmNode* destPos = this; #if NOISY ArpD(cdb << ADH << "Merging " << node << " into " << destPos << endl); #endif const AmTime nodeTime = node->StartTime(); #if NOISY ArpD(cdb << ADH << "Node time is " << nodeTime << endl); #endif AmNode* tmp=NULL; bool searched = false; // If node time is after current position time, look forward for // the place to insert it. while( nodeTime >= destPos->StartTime() ) { #if NOISY ArpD(cdb << ADH << "Dest time is " << destPos->StartTime() << ", going forward." << endl); #endif tmp = destPos->next; if( !tmp ) { // Whoops, ran to end of list -- place source at end. #if NOISY ArpD(cdb << ADH << "This is the last event; appending src.\n"); #endif destPos->InsertNext(node); return B_OK; } destPos = tmp; searched = true; } if( searched ) { // We moved forward at least one event in the dest list, so // we know this is where to put it. #if NOISY ArpD(cdb << ADH << "Found dest time " << destPos->Time() << ", inserting here." << endl); #endif destPos->InsertPrev(node); return B_OK; } // That didn't work -- node time is before current position, so look // back in the list for where this goes. while( nodeTime < destPos->StartTime() ) { #if NOISY ArpD(cdb << ADH << "Dest time is " << destPos->StartTime() << ", going backward." << endl); #endif tmp = destPos->prev; if( !tmp ) { // Whoops, ran to end of list -- place source at front. #if NOISY ArpD(cdb << ADH << "This is the first event; inserting src.\n"); #endif destPos->InsertPrev(node); return B_OK; } destPos = tmp; } // Okay, we absolutely positive know that this is the place to // put it. #if NOISY ArpD(cdb << ADH << "Found dest time " << destPos->StartTime() << ", appending here." << endl); #endif destPos->InsertNext(node); return B_OK; }