static double get_num_beats(const struct SeqTrack *seqtrack, const struct SeqBlock *seqblock, LPB_Iterator *iterator, int audioframes_to_add, const char *from_where, bool *curr_num_beats_is_valid){ struct Blocks *block = seqblock->block; double time = seqtrack->start_time - seqblock->time; #if DEBUG_BUGS R_ASSERT_NON_RELEASE(time > -(RADIUM_BLOCKSIZE*ATOMIC_DOUBLE_GET(block->reltempo))); #endif if (time < 0) // Happens when switching between two seqblocks at a non-audio block alignment (i.e. delta time > 0). To avoid this minor inaccuracy, it seems necessary to break the use of constant 64 frame audio block sizes, so it's probably not worth it. time = 0; double time_to_add = (double)audioframes_to_add * ATOMIC_DOUBLE_GET(block->reltempo); #if DEBUG_BUGS printf("Get num_beats. from_where: %s, time: %f, time_to_add: %f, pc->start_time_f: %f, stime2place: %f\n", from_where, time, time_to_add, ATOMIC_DOUBLE_GET(seqtrack->start_time_f), STime2Place_f(block, time+time_to_add) ); #endif if (time+time_to_add > getBlockSTimeLength(block)) // can happen when switching block *curr_num_beats_is_valid = false; return iterator->num_beats_played_so_far + scale_double(STime2Place_f(block, time+time_to_add), iterator->place1_f, iterator->place2_f, 0.0, iterator->num_beats_between_place1_and_place2 ); }
double RT_LPB_get_current_BPM(const struct SeqTrack *seqtrack){ if (ATOMIC_GET(is_starting_up)) return 120.0; else if (is_playing()) return seqtrack->lpb_iterator.curr_bpm; else { struct Blocks *block = ATOMIC_GET(g_curr_block); if (block==NULL) return (double)root->tempo; else return (double)root->tempo * ATOMIC_DOUBLE_GET(block->reltempo); } }
void PlayerTask(double reltime){ if (ATOMIC_GET(is_starting_up)) return; pc->reltime = reltime; Player_State player_state = ATOMIC_GET(pc->player_state); if (player_state==PLAYER_STATE_PROGRAM_NOT_READY){ //printf("player: program not ready\n"); return; } else if (player_state==PLAYER_STATE_ENDING) { return; } else if (player_state==PLAYER_STATE_STOPPING) { //PC_ReturnElements(); g_time_was_stopped = true; SCHEDULER_reset_all_timing(); if (SCHEDULER_clear_all()) { ATOMIC_SET(pc->player_state, PLAYER_STATE_STOPPED); // Finished. SCHEDULER_clear() cleared everything. //RT_BACKUP_reset_timer(); // Don't want to take backup right after stopping to play. It's quite annoying. (we handle this directly in Qt_AutoBackups instead) player_state = PLAYER_STATE_STOPPED; } else return; // Must run SCHEDULER_clear() at least one more time. We don't want clear too much at once since it could cause CPU spikes. //} else if (player_state==PLAYER_STATE_STOPPED) { // return; } R_ASSERT(player_state==PLAYER_STATE_STARTING_TO_PLAY || player_state==PLAYER_STATE_PLAYING || player_state==PLAYER_STATE_STOPPED); if (player_state != PLAYER_STATE_STOPPED) if(g_time_was_stopped){ OS_InitMidiTiming(); OS_InitAudioTiming(); g_time_was_stopped = false; } bool is_finished = true; ALL_SEQTRACKS_FOR_EACH(){ double reltempo = 1.0; struct SeqBlock *curr_seqblock = seqtrack->curr_seqblock; struct Blocks *block = curr_seqblock==NULL ? NULL : curr_seqblock->block; if(block!=NULL) reltempo = ATOMIC_DOUBLE_GET(block->reltempo); double seqreltime = (double)reltime * reltempo; //if(reltempo!=1.0) // printf("Curr_seqblock: %p. seqrelteim: %f\n", curr_seqblock,seqreltime); pc->is_treating_editor_events = true; { if (SCHEDULER_called_per_block(seqtrack, seqreltime) > 0) is_finished = false; } pc->is_treating_editor_events = false; if (player_state != PLAYER_STATE_STOPPED){ if (curr_seqblock != NULL) { bool set_player_time = false; if (pc->playtype==PLAYBLOCK && seqtrack==&root->song->block_seqtrack) set_player_time = true; else if (pc->playtype==PLAYSONG && seqtrack==root->song->seqtracks.elements[root->song->curr_seqtracknum]) set_player_time = true; if (set_player_time) ATOMIC_DOUBLE_SET(block->player_time, seqtrack->start_time - curr_seqblock->time); //else ATOMIC_DOUBLE_SET(block->player_time, -100); // Not necessary (-100 is set in scheduler_seqtrack.c when switching block), and we also need to check if we are playing block, etc. } } }END_ALL_SEQTRACKS_FOR_EACH; if (player_state==PLAYER_STATE_STOPPED) return; pc->absabstime += RADIUM_BLOCKSIZE; if(pc->playtype==PLAYSONG) { double song_abstime = ATOMIC_DOUBLE_GET(pc->song_abstime); double new_song_abstime = song_abstime + reltime; ATOMIC_DOUBLE_SET(pc->song_abstime, new_song_abstime); } #ifdef WITH_PD RT_PD_set_absolute_time(ATOMIC_DOUBLE_GET(pc->song_abstime)); #endif if (player_state == PLAYER_STATE_STARTING_TO_PLAY) ATOMIC_SET(pc->player_state, PLAYER_STATE_PLAYING); //printf("num_scheduled: %d. state: %d\n",num_scheduled_events,player_state); if(player_state == PLAYER_STATE_PLAYING && is_finished) ATOMIC_SET(pc->player_state, PLAYER_STATE_STOPPING); if(pc->playtype==PLAYSONG){ if (SEQUENCER_is_looping()){ if (ATOMIC_DOUBLE_GET(pc->song_abstime) >= SEQUENCER_get_loop_end()){ ATOMIC_SET(pc->player_state, PLAYER_STATE_STOPPING); } } } }