float Automation::get_tick_val(Tick p_tick) { int block=get_block_idx_at_pos( p_tick ); if (block<0) { /* Check Repeat */ int prev_block=get_prev_block_from_idx( p_tick ); if (prev_block<0 || !get_block( prev_block )->is_repeat_active() ) return -1.0; // adjust block and tick block=prev_block; Tick block_pos=get_block_pos( block ); p_tick=(p_tick - block_pos) % get_block( block )->get_length(); p_tick+=block_pos; } AutomationBlock * b=(AutomationBlock*)BlockList::get_block(block); //cant use dynamic cast here, too slow, sorry there are other checks :( Tick block_tick=p_tick-get_block_pos(block); float res=b->get_data()->get_tick_val(block_tick); //printf("for tick p_tick %g , val is %g\n",(float)p_tick/(float)TICKS_PER_BEAT,res); return res; }
void Track_Pattern::track_block_pre_process(int p_frames,int p_block, Tick p_offset,Tick p_total, Tick p_from, Tick p_to) { EventBuffer &event_buffer=get_event_buffer(); Tick block_pos=get_block_pos(p_block); Tick tick_from_local=p_from; Tick tick_to_local=p_to; if (tick_from_local<0) tick_from_local=0; if (tick_to_local<0) tick_to_local=0; Position pos_from_local(tick_from_local,0); Position pos_to_local(tick_to_local,MAX_COLUMNS); Pattern *pd=get_block(p_block)->get_pattern(); int from_idx; int to_idx; if (!pd->data.find_values_in_range(pos_from_local,pos_to_local,&from_idx,&to_idx)) { //printf("ticks %i to %i have indexes %i to %i\n",(int)tick_from_local,(int)tick_to_local,from_idx,to_idx); for (int i=from_idx;i<=to_idx;i++) { Tick tick=pd->data.get_index_pos(i).tick; if (tick<tick_from_local) continue; if (tick>tick_to_local) break; int col=pd->data.get_index_pos(i).column; if (col<0 || col>=MAX_COLUMNS) continue; //wont play what is not visible int frame=(p_offset+tick)*(p_total)/(Tick)p_frames; //printf("something at %i, in index %i (%i to %i) out of %i\n",(int)tick,i,from_idx,to_idx,pd->data.get_stream_size()); Note n = pd->data.get_index_value(i); if (n.is_note()) { add_noteon_event_to_buffer(n.note,n.volume,col,event_buffer,frame); } else if (n.is_note_off() && data.last_note[col].is_note()) { //printf("AT %i - note off\n",(int)tick_to); Event e; SET_EVENT_MIDI(e,EventMidi::MIDI_NOTE_OFF,0,data.last_note[col].note,0); e.frame_offset=frame; //off te event_buffer.push_event(e); data.last_note[col]=n; } } } }
Track_Pattern::NoteList Track_Pattern::get_notes_in_range(Tick p_from, Tick p_to) { NoteList res; int block_from; int block_to; // printf("get blocks in range %f-%f:",(float)p_from/TICKS_PER_BEAT,(float)p_to/TICKS_PER_BEAT); if (get_blocks_in_rage( p_from, p_to, &block_from, &block_to )) { // printf(" none!\n"); return res; //emty list, nothing fits! } //printf(" %i\n",(block_to-block_from)+1); for (int i=block_from;i<=block_to;i++) { PatternBlock *b = get_block(i); Tick tick_begin=get_block_pos(i); Tick tick_end=tick_begin+b->get_length()-1; int note_from; int note_to; Tick tick_from=(tick_begin<p_from)?p_from:tick_begin; Tick tick_to=(p_to>tick_end)?tick_end:p_to; // printf("scanning block %i, ticks %f-%f\n",i,(float)tick_from/TICKS_PER_BEAT,(float)tick_to/TICKS_PER_BEAT); if (b->get_notes_in_local_range( tick_from-tick_begin, tick_to-tick_begin, ¬e_from, ¬e_to) ) continue; //couldnt find any note //printf("found %i notes\n",note_to-note_from); for (int j=note_from;j<=note_to;j++) { NoteListElement e; e.note=b->get_note( j ); e.pos=b->get_note_pos( j ); e.pos.tick+=get_block_pos( i ); res.push_back(e); } } return res; }
optional<signed_block> block_log::read_block_by_num(uint32_t block_num) const { try { optional<signed_block> b; uint64_t pos = get_block_pos(block_num); if (pos != npos) { b = read_block(pos).first; FC_ASSERT(b->block_num() == block_num, "Wrong block was read from block log.", ("returned", b->block_num())("expected", block_num)); } return b; } FC_LOG_AND_RETHROW() }
Track_Pattern::Note Track_Pattern::get_note(const Position& p_pos) { int pb_idx = get_block_idx_at_pos( p_pos.tick ); ERR_FAIL_COND_V(pb_idx==-1,Note()); PatternBlock *bp=get_block(pb_idx); ERR_FAIL_COND_V(bp==NULL,Note()); Position rel_pos( p_pos.tick-get_block_pos(pb_idx) , p_pos.column ); int tick_idx = bp->get_pattern()->data.get_exact_index(rel_pos); if (tick_idx==INVALID_STREAM_INDEX) return Note(); //return empty note, as pos in tick does not exist */ return bp->get_pattern()->data.get_index_value(tick_idx); }
void Track_Pattern::set_note(const Position& p_pos,const Note& p_note) { int pb_idx = get_block_idx_at_pos( p_pos.tick ); ERR_FAIL_COND(pb_idx==-1); PatternBlock *bp=get_block(pb_idx); ERR_FAIL_COND(bp==NULL); Position rel_pos( p_pos.tick-get_block_pos(pb_idx) , p_pos.column ); if (p_note.is_empty()) { //sets an empty note, delete it */ int tick_idx = bp->get_pattern()->data.get_exact_index( rel_pos ); if (tick_idx==INVALID_STREAM_INDEX) { return; /* nothing to erase */ } bp->get_pattern()->data.erase_index(tick_idx); } else { /* just insert-overwrite wathever you can find */ bp->get_pattern()->data.insert( rel_pos, p_note); } }
void Track_Pattern::track_pre_process(int p_frames) { /* I HATE THIS FUNCTION */ EventBuffer &event_buffer=get_event_buffer(); //add the edit events (if any) at offset 0 for (int i=0;i<data.edit_event_buffer.get_event_count();i++) { Event e=*data.edit_event_buffer.get_event(i); e.frame_offset=0; event_buffer.push_event(e); } data.edit_event_buffer.clear(); if (get_song_playback()->get_status()!=SongPlayback::STATUS_PLAY) { data.old_tick_to=-1; return; //nothing much to do } int block_count=get_block_count(); if (block_count==0) { data.old_tick_to=-1; return; //nuthin' to do } /* Up to where we are going to process. */ Tick tick_to=get_swinged_tick( get_song_playback()->get_current_tick_to() ); Tick tick_from; //from where we process if (data.old_tick_to==-1 || tick_to<data.old_tick_to || abs(tick_to-data.old_tick_to)>TICKS_PER_BEAT) // if previous processing pos is invalid, or position changed tick_from=get_song_playback()->get_current_tick_from(); else tick_from=data.old_tick_to+1; if (tick_from>tick_to) //we already processed up to this tick return; //nothing to do data.old_tick_to=tick_to; int block_idx=get_prev_block_from_idx(tick_from); //printf("PAT: from %i to %i\n",(int)tick_from,(int)tick_to); if (block_idx==-1) { block_idx=0; } while (block_idx<block_count && (get_block_pos(block_idx)<=tick_to) ) { /* process block */ Tick block_pos=get_block_pos(block_idx); Tick block_len=get_block(block_idx)->get_length(); Tick block_end=block_pos+block_len; /* If not inside the block, dont even bother */ if (tick_from<block_end) track_block_pre_process( p_frames, block_idx, 0, tick_to-tick_from, tick_from-block_pos, tick_to-block_pos ); /* Check if this has repeat, and has to be computed! */ if (get_block(block_idx)->is_repeat_active() && tick_to>=block_end) { Tick rep_tick_from=tick_from; Tick rep_tick_to=tick_to; Tick rep_ofs=0; /* Wrap tick to repeat-able-space*/ if (block_idx<(block_count-1) && tick_to>=get_block_pos(block_idx+1)) { rep_tick_to=get_block_pos(block_idx+1)-1; } if (tick_from<block_end) { rep_tick_from=block_end; rep_ofs=block_end-tick_from; } /* convert to local to block positions */ rep_tick_from-=block_pos; rep_tick_to-=block_pos; if (rep_tick_from<=rep_tick_to) { //can do bussiness int from_at_idx=rep_tick_from/block_len; int to_at_idx=rep_tick_to/block_len; /* convert to inside block positions */ rep_tick_from=rep_tick_from%block_len; rep_tick_to=rep_tick_to%block_len; /* process all blocks that need repeat! */ for (int i=from_at_idx;i<=to_at_idx;i++) { Tick from_local=0; Tick to_local=block_len-1; // adjust depending on begin and end if (i==from_at_idx) from_local=rep_tick_from; if (i==to_at_idx) to_local=rep_tick_to; // printf("%i Repeat at %i, %i - inside %i\n",i-from_at_idx,(int)from_local,(int)to_local,(int)block_len); track_block_pre_process( p_frames, block_idx, rep_ofs, tick_to-tick_from, from_local, to_local ); rep_ofs+=block_len-from_local; } } } /* Tick tick_from_local=tick_from-block_pos; Tick tick_to_local=tick_to-block_pos; if (tick_from_local<0) tick_from_local=0; if (tick_to_local<0) tick_to_local=0; Position pos_from_local(tick_from_local,0); Position pos_to_local(tick_to_local,MAX_COLUMNS); Pattern *pd=get_block(block_idx)->get_pattern(); int from_idx; int to_idx; if (!pd->data.find_values_in_range(pos_from_local,pos_to_local,&from_idx,&to_idx)) { //printf("ticks %i to %i have indexes %i to %i\n",(int)tick_from_local,(int)tick_to_local,from_idx,to_idx); for (int i=from_idx;i<=to_idx;i++) { Tick tick=pd->data.get_index_pos(i).tick; if (tick<tick_from_local) continue; if (tick>tick_to_local) break; int col=pd->data.get_index_pos(i).column; if (col<0 || col>=MAX_COLUMNS) continue; //wont play what is not visible int frame=tick*(tick_to-tick_from)/(Tick)p_frames; //printf("something at %i, in index %i (%i to %i) out of %i\n",(int)tick,i,from_idx,to_idx,pd->data.get_stream_size()); Note n = pd->data.get_index_value(i); if (n.is_note()) { add_noteon_event_to_buffer(n.note,n.volume,col,event_buffer,frame); } else if (n.is_note_off() && data.last_note[col].is_note()) { //printf("AT %i - note off\n",(int)tick_to); Event e; SET_EVENT_MIDI(e,EventMidi::MIDI_NOTE_OFF,0,data.last_note[col].note,0); e.frame_offset=frame; //off te event_buffer.push_event(e); data.last_note[col]=n; } } } */ /* Process note OFFs at end of block */ /* Is there a reason for this? Tick block_len=get_block(block_idx)->get_length(); if (tick_from_local<=block_len && tick_to_local>=block_len) { int frame=block_len*(tick_to_local-tick_from_local)/(Tick)p_frames; for (int i=0;i<MAX_COLUMNS;i++) { if (data.last_note[i].is_note()) { //printf("AT %i - note off\n",(int)tick_to); Event e; SET_EVENT_MIDI(e,EventMidi::MIDI_NOTE_OFF,0,data.last_note[i].note,0); e.frame_offset=frame; //off te event_buffer.push_event(e); data.last_note[i]=Note(Note::NOTE_OFF); } } } */ block_idx++; } }