void RT_schedule_LPBs_newblock(struct SeqTrack *seqtrack, const struct SeqBlock *seqblock, const Place start_place) { LPB_Iterator *iterator = &seqtrack->lpb_iterator; // Null out all fields, except num_beats_played_so_far. double num_beats_played_so_far = iterator->num_beats_played_so_far + iterator->num_beats_between_place1_and_place2; memset(iterator, 0, sizeof(LPB_Iterator)); iterator->num_beats_played_so_far = num_beats_played_so_far; const struct Blocks *block = seqblock->block; const struct LPBs *lpb = block->lpbs; if (lpb==NULL) { set_iterator_data2(iterator, block, PlaceFirstPos, root->lpb, NULL); } else if (PlaceGreaterThan(&lpb->l.p, &start_place)){ set_iterator_data2(iterator, block, PlaceFirstPos, root->lpb, lpb); schedule_next_LPB(seqtrack, seqblock, lpb); } else { const struct LPBs *next_lpb = NextLPB(lpb); // spool forward to the 'lpb' that is used by 'start_place' // while(next_lpb != NULL){ if (PlaceGreaterThan(&next_lpb->l.p, &start_place)) break; lpb = next_lpb; next_lpb = NextLPB(lpb); } set_iterator_data(iterator, block, lpb); if (next_lpb != NULL) schedule_next_LPB(seqtrack, seqblock, next_lpb); } R_ASSERT(iterator->lpb_value != 0); }
void ListAddElement3_a( void *voidlistroot, struct ListHeader3 *element ){ struct ListHeaderPointer3 *listroot=voidlistroot; struct ListHeader3 *prev=NULL; struct ListHeader3 *temp=listroot->root; if(element==NULL) return; while(temp!=NULL){ if(PlaceGreaterThan(&temp->p,&element->p)) break; prev=temp; temp=temp->next; } if(prev==NULL){ R_ASSERT_RETURN_IF_FALSE(element!=NULL); element->next=listroot->root; listroot->root=element; }else{ R_ASSERT_RETURN_IF_FALSE(element!=NULL); element->next=prev->next; prev->next=element; } }
/************************************************************** FUNCTION Set the _end attributes for note 'note'. Finds next note to stop at, or block length. **************************************************************/ void SetEndAttributes( const struct Blocks *block, const struct Tracks *track, struct Notes *note ){ Place *place; Place *p1=NULL,*p2=NULL; bool endSetEarlier = PlaceGreaterThan(¬e->end, ¬e->l.p); Place *earliest = endSetEarlier ? ¬e->end : ¬e->l.p; struct ListHeader3 *nextnote=note->l.next; while(nextnote!=NULL){ if(PlaceGreaterThan(&nextnote->p, earliest)){ p1 = &nextnote->p; break; } nextnote=nextnote->next; } struct ListHeader3 *stop= &track->stops->l; while(stop!=NULL){ if(PlaceGreaterThan(&stop->p, earliest)){ p2 = &stop->p; break; } stop=stop->next; } place=PlaceMin(p1,p2); if(place!=NULL){ note->end.line=place->line; note->end.counter=place->counter; note->end.dividor=place->dividor; }else{ PlaceSetLastPos(block, ¬e->end); note->noend=1; } ValidatePlace(¬e->end); }
void TRACK_make_monophonic_destructively(struct Tracks *track){ struct Tracker_Windows *window = root->song->tracker_windows; struct WBlocks *wblock = window->wblock; struct Notes *note = track->notes; bool have_made_undo = false; while(note!=NULL){ struct Notes *next = NextNote(note); if (next==NULL) break; if (PlaceGreaterThan(¬e->end, &next->l.p)){ PLAYER_lock();{ if (PlaceEqual(¬e->l.p, &next->l.p)) { ListRemoveElement3(&track->notes, &next->l); } else { PlaceCopy(¬e->end, &next->l.p); note = next; } }PLAYER_unlock(); if (have_made_undo==false){ ADD_UNDO(Notes(window, wblock->block, track, wblock->curr_realline ) ); have_made_undo = true; } } else { note = next; } } if (have_made_undo==false) GFX_Message(NULL, "Track is already monophonic"); else window->must_redraw = true; }
/********************************************************************** FUNCTION Set the end attributes of all notes that previously was stopped at position 'placement' to the next stop wherever that may be. **********************************************************************/ void LengthenNotesTo( struct Blocks *block, struct Tracks *track, Place *placement ){ struct Notes *note=track->notes; while(note!=NULL){ if(PlaceGreaterThan(¬e->l.p,placement)) break; if(PlaceEqual(¬e->end,placement)) SetEndAttributes(block,track,note); note=NextNote(note); } }
/* Nearly the same, except that it cuts first one that is placed _after_ 'place' */ void CutListAt_a(void *listroot,Place *place){ struct ListHeaderPointer3 *root=(struct ListHeaderPointer3 *)listroot; struct ListHeader3 *element=root->root; if(element==NULL) return; if(PlaceGreaterThan(&element->p,place)){ root->root=NULL; return; } for(;element!=NULL;element=element->next){ if( element->next!=NULL && PlaceGreaterThan(&element->next->p,place) ){ element->next=NULL; break; } } }
/********************************************************************** FUNCTION Set the end attributes of all notes that previously was stopped at position 'old_placement' to 'new_placement'. **********************************************************************/ void ReplaceNoteEnds( struct Blocks *block, struct Tracks *track, Place *old_placement, Place *new_placement, int polyphony_num ){ struct Notes *note=track->notes; while(note!=NULL){ if (note->polyphony_num == polyphony_num) { if(PlaceGreaterThan(¬e->l.p,old_placement)) break; if(PlaceEqual(¬e->end,old_placement)) { note->end = *new_placement; NOTE_validate(block, track, note); } } note=NextNote(note); } }
void RT_schedule_Signature_newblock(struct SeqTrack *seqtrack, const struct SeqBlock *seqblock, const Place start_place) { Signature_Iterator *iterator = &seqtrack->signature_iterator; memset(iterator, 0, sizeof(Signature_Iterator)); iterator->signature_value = root->signature; //printf(" SIG Init %d/%d\n",iterator->signature_value.numerator, iterator->signature_value.denominator); const struct Blocks *block = seqblock->block; const struct Signatures *next_signature = block->signatures; if(next_signature==NULL) return; // spool forward to the 'signature' that is used by 'start_place' // while(PlaceGreaterThan(&start_place, &next_signature->l.p)){ iterator->signature_value = next_signature->signature; //printf(" SIG Init %d/%d\n",iterator->signature_value.numerator, iterator->signature_value.denominator); next_signature = NextSignature(next_signature); if (next_signature==NULL) return; } iterator->next_signature = next_signature; { int num_args = 1; union SuperType args[num_args]; args[0].const_pointer = seqblock; int64_t time = get_seqblock_place_time(seqblock, next_signature->l.p); SCHEDULER_add_event(seqtrack, time, RT_scheduled_Signature, &args[0], num_args, SCHEDULER_SIGNATURE_PRIORITY); } }
/************************************************************** FUNCTION Stops all notes before line+(counter/dividor) at line+(counter/dividor, if they last that long. **************************************************************/ void StopAllNotesAtPlace( struct Blocks *block, struct Tracks *track, Place *placement ){ if (PLAYER_current_thread_has_lock()==false && is_playing()==true){ RError("StopAllNotesAtPlace. PLAYER_current_thread_has_lock(): %d, is_playing(): %d", PLAYER_current_thread_has_lock()==false, is_playing()==true); } struct Notes *temp; temp=track->notes; while(temp!=NULL && PlaceLessThan(&temp->l.p,placement)){ if(PlaceGreaterThan(&temp->end,placement)){ CutListAt(&temp->velocities,placement); CutListAt(&temp->pitches,placement); PlaceCopy(&temp->end,placement); NOTE_validate(block, track, temp); } temp=NextNote(temp); } }
void TRACK_split_into_monophonic_tracks(struct Tracker_Windows *window, struct WBlocks *wblock, struct WTracks *wtrack){ PlayStop(); // This function is too chaotic. Don't bother pausing player. vector_t notesvector = {0}; struct Tracks *track = wtrack->track; struct Notes *notes = track->notes; struct Notes *notes_nexttrack = NULL; bool have_made_undo = false; if (NOTES_sorted_by_pitch_questionmark(track->notes)==false) { ADD_UNDO(Block_CurrPos(window)); have_made_undo = true; notes = NOTES_sort_by_pitch(notes); } while(notes != NULL){ struct Notes *notes_root = notes; while(notes != NULL) { struct Notes *next = NextNote(notes); if (next==NULL) break; if (PlaceGreaterThan(¬es->end, &next->l.p)){ if (have_made_undo==false) { have_made_undo=true; } ListRemoveElement3(¬es, &next->l); ListAddElement3_a(¬es_nexttrack, &next->l); } else notes = next; } VECTOR_push_back(¬esvector, notes_root); notes = notes_nexttrack; notes_nexttrack = NULL; } if (have_made_undo==false){ GFX_Message(NULL, "Track is already monophonic"); return; } int num_tracks = notesvector.num_elements; track->notes = NULL; struct WTracks *wtrack_copy = CB_CopyTrack(wblock,wtrack); VECTOR_clean(&wtrack_copy->track->fxs); InsertTracks(window, wblock, wtrack->l.num+1, num_tracks-1); printf("Vector length: %d\n",num_tracks); int i; for(i=0;i<num_tracks;i++){ struct Notes *notes = notesvector.elements[i]; printf(" %d: %d\n", i, ListFindNumElements3(¬es->l)); while(notes != NULL){ printf(" %s\n",NotesTexts3[(int)notes->note]); notes = NextNote(notes); } struct WTracks *towtrack = ListFindElement1(&wblock->wtracks->l, wtrack->l.num+i); if (i>0) co_CB_PasteTrack(wblock, wtrack_copy, towtrack); towtrack->track->notes = notesvector.elements[i]; } window->must_redraw = true; }
static const struct NodeLine *create_nodelines( const struct Tracker_Windows *window, const struct WBlocks *wblock, const struct ListHeader3 *list, float (*get_x)(const struct WBlocks *wblock, const struct ListHeader3 *element, int *logtype), // should return a value between 0 and 1. const struct ListHeader3 *last_element // may be null. may also contain more than one element. ) { struct NodeLine *nodelines = NULL; R_ASSERT(list != NULL); R_ASSERT(list->next != NULL || last_element!=NULL); if (last_element!=NULL){ const Place *start = &list->p; const Place *end = &last_element->p; R_ASSERT(PlaceGreaterThan(end, start)); } // 1. Create straight forward nodelines from the list { float reallineF = 0.0f; struct NodeLine *nodelines_last = NULL; while(list != NULL){ struct NodeLine *nodeline = (struct NodeLine *)talloc(sizeof(struct NodeLine)); nodeline->x1 = get_x(wblock, list, &nodeline->logtype); reallineF = FindReallineForF(wblock, reallineF, &list->p); nodeline->y1 = get_realline_y(window, reallineF); nodeline->element1 = list; nodeline->is_node = true; if(nodelines_last==NULL) nodelines = nodelines_last = nodeline; else { nodelines_last->next = nodeline; nodelines_last = nodeline; } list = list->next; if (list==NULL) { list = last_element; last_element = NULL; } } } // 2. Insert x2, y2 and element2 attributes, and remove last element. { R_ASSERT_RETURN_IF_FALSE2(nodelines!=NULL, NULL); // shouldn't be possible, but I got a crash report that indicates that this might have happened. R_ASSERT_RETURN_IF_FALSE2(nodelines->next!=NULL, NULL); // shouldn't be possible either, but more likely than the line above. struct NodeLine *ns = nodelines; struct NodeLine *next = ns->next; for(;;){ ns->x2 = ns->logtype==LOGTYPE_HOLD ? ns->x1 : next->x1; ns->y2 = next->y1; if (ns->y2 < ns->y1) { RWarning("y2 < y1: %f < %f",ns->y2,ns->y1); ns->y2 = ns->y1; } ns->element2 = next->element1; if(next->next==NULL) break; ns = next; next = next->next; } ns->next = NULL; // Cut the last element } // 3. Insert all non-node break-points. (caused by realline level changes) { struct LocalZooms **reallines=wblock->reallines; int curr_level = reallines[0]->level; int realline; float reallineF = 0.0f; for(realline = 1; realline < wblock->num_reallines ; realline++) { struct LocalZooms *localzoom = reallines[realline]; if (localzoom->level != curr_level){ reallineF = FindReallineForF(wblock, reallineF, &localzoom->l.p); insert_nonnode_nodeline(nodelines, &localzoom->l, get_realline_y(window, reallineF)); curr_level = localzoom->level; } } } return nodelines; }
static void set_legal_start_and_end_pos(const struct Blocks *block, struct Tracks *track, struct Notes *note){ Place *start = ¬e->l.p; Place *end = ¬e->end; Place endplace; PlaceSetLastPos(block,&endplace); if(PlaceGreaterOrEqual(start,&endplace)) { RError("note is placed after block end. start: %f, end: %f", GetfloatFromPlace(¬e->l.p), GetfloatFromPlace(¬e->end)); set_new_position(track, note, PlaceCreate(block->num_lines - 2, 0, 1), NULL); start = ¬e->l.p; } if (start->line < 0) { RError("note is placed before block start. start: %f, end: %f", GetfloatFromPlace(¬e->l.p), GetfloatFromPlace(¬e->end)); set_new_position(track, note, PlaceCreate(0,1,1), NULL); start = ¬e->l.p; } if(PlaceGreaterThan(end,&endplace)) { RError("note end is placed after block end. start: %f, end: %f. block end: %f", GetfloatFromPlace(¬e->l.p), GetfloatFromPlace(¬e->end), GetfloatFromPlace(&endplace)); set_new_position(track, note, NULL, &endplace); end = ¬e->end; } if (note->velocities != NULL) { { struct Velocities *first_velocity = note->velocities; if(PlaceGreaterThan(start, &first_velocity->l.p)){ RError("note start is placed after first velocity. start: %f, first: %f, end: %f", GetfloatFromPlace(¬e->l.p), GetfloatFromPlace(&first_velocity->l.p), GetfloatFromPlace(¬e->end)); float e = p_float(first_velocity->l.p); e -= 0.01; e = R_MAX(0.0, e); Place new_start; Float2Placement(e, &new_start); set_new_position(track, note, &new_start, NULL); start = ¬e->l.p; } } struct Velocities *last_velocity = (struct Velocities*)ListLast3(¬e->velocities->l); if(PlaceLessThan(end, &last_velocity->l.p)){ RError("note end is placed before last velocity. start: %f, last: %f, end: %f", GetfloatFromPlace(¬e->l.p), GetfloatFromPlace(&last_velocity->l.p), GetfloatFromPlace(¬e->end)); float e = p_float(last_velocity->l.p); e += 0.01; Place new_end; Float2Placement(e, &new_end); set_new_position(track, note, NULL, &new_end); end = ¬e->end; } } if (note->pitches != NULL) { { struct Pitches *first_pitch = note->pitches; if(PlaceGreaterThan(start, &first_pitch->l.p)){ RError("note start is placed after first pitch. start: %f, first: %f, end: %f", GetfloatFromPlace(¬e->l.p), GetfloatFromPlace(&first_pitch->l.p), GetfloatFromPlace(¬e->end)); float e = p_float(first_pitch->l.p); e -= 0.01; e = R_MAX(0.0, e); Place new_start; Float2Placement(e, &new_start); set_new_position(track, note, &new_start, NULL); start = ¬e->l.p; } } struct Pitches *last_pitch = (struct Pitches*)ListLast3(¬e->pitches->l); if(PlaceLessThan(end, &last_pitch->l.p)){ RError("note end is placed before last pitch. start: %f, last: %f, end: %f", GetfloatFromPlace(¬e->l.p), GetfloatFromPlace(&last_pitch->l.p), GetfloatFromPlace(¬e->end)); float e = p_float(last_pitch->l.p); e += 0.01; Place new_end; Float2Placement(e, &new_end); set_new_position(track, note, NULL, &new_end); end = ¬e->end; } } if(PlaceLessOrEqual(end,start)) { RError("note end is placed before (or on) note start. start: %f, end: %f", GetfloatFromPlace(¬e->l.p), GetfloatFromPlace(¬e->end)); float e = p_float(*start); e += 0.01; Place new_end; Float2Placement(e, &new_end); set_new_position(track, note, NULL, &new_end); } }