delete nested_output[i];
}
-int AModuleResample::read_samples(Samples *buffer, int64_t start, int64_t len)
+int AModuleResample::read_samples(Samples *buffer,
+ int64_t start, int64_t len, int direction)
{
- int result = 0;
-
-
- if(module->asset)
- {
-// Files only read going forward.
- if(get_direction() == PLAY_REVERSE)
- {
- start -= len;
- }
-
-//printf("AModuleResample::read_samples start=%jd len=%jd\n", start, len);
- module->file->set_audio_position(start);
- module->file->set_channel(module->channel);
- result = module->file->read_samples(buffer, len);
-
-// Reverse buffer so resampling filter renders forward.
- if(get_direction() == PLAY_REVERSE)
- Resample::reverse_buffer(buffer->get_data(), len);
- }
- else
- if(module->nested_edl)
- {
-
-
-// Nested EDL generates reversed buffer.
- for(int i = 0; i < module->nested_edl->session->audio_channels; i++)
- {
- if(nested_allocation < len)
- {
- delete nested_output[i];
- nested_output[i] = 0;
- }
-
- if(!nested_output[i])
- {
- nested_output[i] = new Samples(len);
- }
- }
-
-
- result = module->nested_renderengine->arender->process_buffer(
- nested_output,
- len,
- start);
-// printf("AModuleResample::read_samples buffer=%p module=%p len=%d\n",
-// buffer,
-// module,
-// len);
- memcpy(buffer->get_data(),
- nested_output[module->channel]->get_data(),
- len * sizeof(double));
-
- }
- return result;
+ return module->read_samples(buffer, start, len, direction);
}
-
-
-
-
-
-
-
-
-
-
AModule::AModule(RenderEngine *renderengine,
CommonRender *commonrender,
PluginArray *plugin_array,
: Module(renderengine, commonrender, plugin_array, track)
{
data_type = TRACK_AUDIO;
+ channel = 0;
transition_temp = 0;
speed_temp = 0;
bzero(nested_output, sizeof(Samples*) * MAX_CHANNELS);
delete resample;
}
+int AModule::read_samples(Samples *buffer, int64_t start, int64_t len, int direction)
+{
+ if( len < 0 ) return 1;
+ double *buffer_data = buffer->get_data();
+// if start < 0, zero fill prefix. if error, zero fill buffer
+ int64_t zeros = len;
+ int result = 0;
+ if( asset ) {
+// Files only read going forward.
+ if( direction == PLAY_REVERSE ) start -= len;
+ int64_t sz = start >= 0 ? len : len + start;
+ if( start < 0 ) start = 0;
+ if( sz > 0 ) {
+ file->set_audio_position(start);
+ file->set_channel(channel);
+ result = file->read_samples(buffer, sz);
+ if( !result && (zeros-=sz) > 0 ) {
+ double *top_data = buffer_data + zeros;
+ memmove(top_data, buffer_data, sz*sizeof(*buffer_data));
+ }
+ }
+ if( !result && direction == PLAY_REVERSE )
+ Resample::reverse_buffer(buffer_data, len);
+ }
+ else if( nested_edl ) {
+ if( nested_allocation < len ) {
+ nested_allocation = len;
+ for( int i=0; i<nested_edl->session->audio_channels; ++i ) {
+ delete nested_output[i];
+ nested_output[i] = new Samples(nested_allocation);
+ }
+ }
+ result = nested_renderengine->arender->
+ process_buffer(nested_output, len, start);
+ if( !result ) {
+ double *sample_data = nested_output[channel]->get_data();
+ int buffer_size = len * sizeof(*buffer_data);
+ memcpy(buffer_data, sample_data, buffer_size);
+ zeros = 0;
+ }
+ }
+ if( zeros > 0 )
+ memset(buffer_data, 0, zeros*sizeof(*buffer_data));
+ return result;
+}
+
AttachmentPoint* AModule::new_attachment(Plugin *plugin)
{
return new AAttachmentPoint(renderengine, plugin);
int AModule::import_samples(AEdit *edit,
- int64_t start_project,
- int64_t edit_startproject,
- int64_t edit_startsource,
- int direction,
- int sample_rate,
- Samples *buffer,
- int64_t fragment_len)
+ int64_t start_project, int64_t edit_startproject, int64_t edit_startsource,
+ int direction, int sample_rate, Samples *buffer, int64_t fragment_len)
{
- const int debug = 0;
int result = 0;
-// start in EDL samplerate
- int64_t start_source = start_project - edit_startproject + edit_startsource;
-// fragment size adjusted for speed curve
- int64_t speed_fragment_len = fragment_len;
-// boundaries of input fragment required for speed curve
- double max_position = 0;
- double min_position = 0;
-
- double speed_position = edit_startsource;
-// position in source where speed curve starts reading
- double speed_position1 = speed_position;
-// position in source where speed curve finishes
- double speed_position2 = speed_position;
-// Need speed curve processing
- int have_speed = 0;
-// Temporary buffer for rendering speed curve
+ if( fragment_len <= 0 )
+ result = 1;
+ if( nested_edl && edit->channel >= nested_edl->session->audio_channels )
+ result = 1;
+ double *buffer_data = buffer->get_data();
+// buffer fragment adjusted for speed curve
Samples *speed_buffer = buffer;
+ double *speed_data = speed_buffer->get_data();
+ int64_t speed_fragment_len = fragment_len;
+ int dir = direction == PLAY_FORWARD ? 1 : -1;
+// normal speed source boundaries in EDL samplerate
+ int64_t start_source = start_project - edit_startproject + edit_startsource;
+ double end_source = start_source + dir*speed_fragment_len;
+ double start_position = start_source;
+// double end_position = end_source;
+// normal speed playback boundaries
+ double min_source = bmin(start_source, end_source);
+ double max_source = bmax(start_source, end_source);
- if( nested_edl && edit->channel >= nested_edl->session->audio_channels )
- return 1;
this->channel = edit->channel;
- int dir = direction == PLAY_FORWARD ? 1 : -1;
+ int have_speed = track->has_speed();
// apply speed curve to source position so the timeline agrees with the playback
- if( track->has_speed() ) {
-// get speed adjusted position from start of edit.
+ if( !result && have_speed ) {
+// get speed adjusted start position from start of edit.
FloatAuto *previous = 0, *next = 0;
FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
- speed_position += speed_autos->automation_integral(edit_startproject,
+ double source_position = edit_startsource +
+ speed_autos->automation_integral(edit_startproject,
start_project-edit_startproject, PLAY_FORWARD);
- speed_position1 = speed_position;
-
+ min_source = source_position;
+ max_source = source_position;
// calculate boundaries of input fragment required for speed curve
- max_position = speed_position;
- min_position = speed_position;
int64_t pos = start_project;
- for( int64_t i=0; i<fragment_len; ++i,pos+=dir ) {
+ start_position = source_position;
+ for( int64_t i=fragment_len; --i>=0; pos+=dir ) {
double speed = speed_autos->get_value(pos, direction, previous, next);
- speed_position += dir*speed;
- if(speed_position > max_position) max_position = speed_position;
- if(speed_position < min_position) min_position = speed_position;
- }
-
- speed_position2 = speed_position;
- if(speed_position2 < speed_position1)
- {
- max_position += 1.0;
-// min_position -= 1.0;
- speed_fragment_len = (int64_t)(max_position - min_position);
- }
- else
- {
- max_position += 1.0;
- speed_fragment_len = (int64_t)(max_position - min_position);
+ source_position += dir*speed;
+ if( source_position > max_source ) max_source = source_position;
+ if( source_position < min_source ) min_source = source_position;
}
-
-//printf("AModule::import_samples %d %f %f %f %f\n",
-// __LINE__, min_position, max_position, speed_position1, speed_position2);
-
-// new start of source to read from file
- start_source = (int64_t)min_position;
- have_speed = 1;
-
+// end_position = source_position;
+ speed_fragment_len = (int64_t)(max_source - min_source);
+ start_source = direction == PLAY_FORWARD ? min_source : max_source;
+ if( speed_fragment_len > 0 ) {
// swap in the temp buffer
- if(speed_temp && speed_temp->get_allocated() < speed_fragment_len) {
- delete speed_temp; speed_temp = 0;
+ if( speed_temp && speed_temp->get_allocated() < speed_fragment_len ) {
+ delete speed_temp; speed_temp = 0;
+ }
+ if( !speed_temp )
+ speed_temp = new Samples(speed_fragment_len);
+ speed_buffer = speed_temp;
+ speed_data = speed_buffer->get_data();
}
- if(!speed_temp)
- speed_temp = new Samples(speed_fragment_len);
- speed_buffer = speed_temp;
}
- if( speed_fragment_len == 0 )
- return 1;
+ int edit_sample_rate = 0;
+ if( speed_fragment_len <= 0 )
+ result = 1;
-// Source is a nested EDL
- if( edit->nested_edl ) {
- int command = direction == PLAY_REVERSE ?
- NORMAL_REWIND : NORMAL_FWD;
+ if( !result && edit->asset ) {
+ nested_edl = 0;
+ if( nested_renderengine ) {
+ delete nested_renderengine; nested_renderengine = 0;
+ }
+// Source is an asset
+ asset = edit->asset;
+ edit_sample_rate = asset->sample_rate;
+ get_cache()->age();
+ file = get_cache()->check_out(asset, get_edl());
+ if( !file ) {
+ printf(_("AModule::import_samples Couldn't open %s.\n"), asset->path);
+ result = 1;
+ }
+ }
+ else if( !result && edit->nested_edl ) {
asset = 0;
-
+// Source is a nested EDL
if( !nested_edl || nested_edl->id != edit->nested_edl->id ) {
nested_edl = edit->nested_edl;
- if( nested_renderengine ) {
- delete nested_renderengine; nested_renderengine = 0;
- }
- if( !nested_command )
- nested_command = new TransportCommand;
- if( !nested_renderengine ) {
- nested_command->command = command;
- nested_command->get_edl()->copy_all(nested_edl);
- nested_command->change_type = CHANGE_ALL;
- nested_command->realtime = renderengine->command->realtime;
- nested_renderengine = new RenderEngine(0, get_preferences(), 0, 1);
- nested_renderengine->set_acache(get_cache());
-// Must use a private cache for the audio
-// if(!cache)
-// {
-// cache = new CICache(get_preferences());
-// private_cache = 1;
-// }
-// nested_renderengine->set_acache(cache);
- nested_renderengine->arm_command(nested_command);
- }
+ delete nested_renderengine;
+ nested_renderengine = 0;
}
-if(debug) printf("AModule::import_samples %d speed_fragment_len=%d\n", __LINE__, (int)speed_fragment_len);
-
-// Allocate output buffers for all channels
- for( int i=0; i<nested_edl->session->audio_channels; ++i ) {
- if( nested_allocation < speed_fragment_len ) {
- delete nested_output[i]; nested_output[i] = 0;
- }
- if(!nested_output[i])
- nested_output[i] = new Samples(speed_fragment_len);
+ edit_sample_rate = nested_edl->session->sample_rate;
+ int command = direction == PLAY_REVERSE ?
+ NORMAL_REWIND : NORMAL_FWD;
+ if( !nested_command ) {
+ nested_command = new TransportCommand;
+ nested_command->command = command;
+ nested_command->get_edl()->copy_all(nested_edl);
+ nested_command->change_type = CHANGE_ALL;
+ nested_command->realtime = renderengine->command->realtime;
+ }
+ if( !nested_renderengine ) {
+ nested_renderengine = new RenderEngine(0, get_preferences(), 0, 1);
+ nested_renderengine->set_acache(get_cache());
+ nested_renderengine->arm_command(nested_command);
}
-
- if( nested_allocation < speed_fragment_len )
- nested_allocation = speed_fragment_len;
-
-// Update direction command
nested_renderengine->command->command = command;
+ result = 0;
+ }
-// Render the segment
- if( !nested_renderengine->arender )
- bzero(speed_buffer->get_data(), speed_fragment_len * sizeof(double));
- else if(sample_rate != nested_edl->session->sample_rate) {
+ if( !result ) {
+// speed_buffer is (have_speed ? speed_temp : buffer)
+ if( sample_rate != edit_sample_rate ) {
if( !resample )
resample = new AModuleResample(this);
result = resample->resample(speed_buffer,
- speed_fragment_len, nested_edl->session->sample_rate,
+ speed_fragment_len, edit_sample_rate,
sample_rate, start_source, direction);
-// Resample reverses to keep it running forward.
}
else {
-// Render without resampling
- result = nested_renderengine->arender->process_buffer(
- nested_output, speed_fragment_len, start_source);
- memcpy(speed_buffer->get_data(),
- nested_output[edit->channel]->get_data(),
- speed_fragment_len * sizeof(double));
-
-// Reverse fragment so ::render can apply transitions going forward.
- if( direction == PLAY_REVERSE ) {
- Resample::reverse_buffer(speed_buffer->get_data(), speed_fragment_len);
- }
+ result = read_samples(speed_buffer,
+ start_source, speed_fragment_len, direction);
}
}
- else if( edit->asset ) {
-// Source is an asset
- nested_edl = 0;
- asset = edit->asset;
- get_cache()->age();
-
- if( nested_renderengine ) {
- delete nested_renderengine; nested_renderengine = 0;
- }
-
- if( !(file = get_cache()->check_out( asset, get_edl())) ) {
-// couldn't open source file / skip the edit
- printf(_("AModule::import_samples Couldn't open %s.\n"), asset->path);
- result = 1;
- }
- else {
- result = 0;
-
- if( sample_rate != asset->sample_rate ) {
-// Read through sample rate converter.
- if( !resample )
- resample = new AModuleResample(this);
- result = resample->resample(speed_buffer,
- speed_fragment_len, asset->sample_rate,
- sample_rate, start_source, direction);
-// Resample reverses to keep it running forward.
- }
- else {
- file->set_audio_position(start_source);
- file->set_channel(edit->channel);
- result = file->read_samples(speed_buffer, speed_fragment_len);
-// Reverse fragment so ::render can apply transitions going forward.
- if(direction == PLAY_REVERSE)
- Resample::reverse_buffer(speed_buffer->get_data(), speed_fragment_len);
- }
-
- get_cache()->check_in(asset);
- file = 0;
- }
- }
- else {
- nested_edl = 0;
- asset = 0;
- if( speed_fragment_len > 0 )
- bzero(speed_buffer->get_data(), speed_fragment_len * sizeof(double));
+ if( asset && file ) {
+ file = 0;
+ get_cache()->check_in(asset);
}
-
// Stretch it to fit the speed curve
// Need overlapping buffers to get the interpolation to work, but this
// screws up sequential effects.
- if( have_speed ) {
- double *buffer_samples = buffer->get_data();
- if( speed_fragment_len > 0 ) {
- FloatAuto *previous = 0;
- FloatAuto *next = 0;
- FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
- double *speed_samples = speed_buffer->get_data();
- int len1 = speed_fragment_len-1;
- int out_offset = dir>0 ? 0 : fragment_len-1;
- speed_position = speed_position1;
+ if( !result && have_speed ) {
+ FloatAuto *previous = 0, *next = 0;
+ FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
+ int len1 = speed_fragment_len-1;
+ double speed_position = start_position;
+ double pos = start_project;
+// speed gnuplot> plot "/tmp/x.dat" using($1) with lines
+// speed_position gnuplot> plot "/tmp/x.dat" using($2) with lines
+//FILE *fp = 0;
+//if( !channel ) { fp = fopen("/tmp/x.dat", "a"); fprintf(fp," %f %f\n",0.,0.); }
+ for( int64_t i=0; i<fragment_len; ++i,pos+=dir ) {
int64_t speed_pos = speed_position;
-
- int64_t pos = start_project;
- for( int64_t i=0; i<fragment_len; ++i,pos+=dir ) {
- double speed = speed_autos->get_value(pos,
- direction, previous, next);
- double next_position = speed_position + dir*speed;
- int64_t next_pos = next_position;
+ double speed = speed_autos->get_value(pos,
+ direction, previous, next);
+//if(fp) fprintf(fp," %f %f\n", speed, speed_position);
+ double next_position = speed_position + dir*speed;
+ int64_t next_pos = next_position;
+ int total = abs(next_pos - speed_pos);
+ int k = speed_pos - min_source;
+ if( dir < 0 ) k = len1 - k; // if buffer reversed
+ double sample = speed_data[bclip(k, 0,len1)];
+ if( total > 1 ) {
int d = next_pos >= speed_pos ? 1 : -1;
- int k = speed_pos - start_source;
- double sample = speed_samples[bclip(k, 0,len1)];
- int total = abs(next_pos - speed_pos);
- if( total > 1 ) {
- for( int j=total; --j>0; ) {
- k += d;
- sample += speed_samples[bclip(k, 0,len1)];
- }
- sample /= total;
- }
-#if 0
- else if( total < 1 ) {
+ for( int j=total; --j>0; ) {
k += d;
- double next_sample = speed_samples[bclip(k, 0,len1)];
- double v = speed_position - speed_pos;
- sample = (1.-v) * sample + v * next_sample;
+ sample += speed_data[bclip(k, 0,len1)];
}
-#endif
- buffer_samples[out_offset] = sample;
- out_offset += dir;
- speed_position = next_position;
- speed_pos = next_pos;
+ sample /= total;
+ }
+#if 0
+ else if( total < 1 ) {
+ int d = next_pos >= speed_pos ? 1 : -1;
+ k += d;
+ double next_sample = speed_data[bclip(k, 0,len1)];
+ double v = speed_position - speed_pos;
+ sample = (1.-v) * sample + v * next_sample;
}
+#endif
+ buffer_data[i] = sample;
+ speed_position = next_position;
}
+//if(fp) fclose(fp);
}
+ if( result )
+ bzero(buffer_data, fragment_len*sizeof(*buffer_data));
return result;
}
}
}
if(debug) printf("AModule::render %d start_position=%jd end_position=%jd fragment_len=%jd\n",
-__LINE__,
-start_position,
-end_position,
-fragment_len);
+ __LINE__, start_position, end_position, fragment_len);
if(direction == PLAY_REVERSE)
{
~AModuleResample();
// All positions are in source sample rate
- int read_samples(Samples *buffer, int64_t start, int64_t len);
+ int read_samples(Samples *buffer,
+ int64_t start, int64_t len, int direction);
AModule *module;
// output for nested EDL if resampled
CICache* get_cache();
int import_samples(AEdit *playable_edit,
- int64_t start_project,
- int64_t edit_startproject,
- int64_t edit_startsource,
- int direction,
- int sample_rate,
- Samples *buffer,
- int64_t fragment_len);
-
-
+ int64_t start_project, int64_t edit_startproject, int64_t edit_startsource,
+ int direction, int sample_rate, Samples *buffer, int64_t fragment_len);
int render(Samples *buffer,
- int64_t input_len,
- int64_t input_position,
- int direction,
- int sample_rate,
- int use_nudge);
+ int64_t input_len, int64_t input_position, int direction,
+ int sample_rate, int use_nudge);
+ int read_samples(Samples *buffer,
+ int64_t start, int64_t len, int direction);
int get_buffer_size();
AttachmentPoint* new_attachment(Plugin *plugin);
{
BC_WindowBase *window = get_canvas();
if( !window ) return;
-
int window_w = window->get_w();
int window_h = window->get_h();
+ int color = get_clear_color();
+ window->set_color(color);
+
+ if( !edl ) {
+ window->draw_box(0, 0, window_w, window_h);
+ window->flash(0);
+ return;
+ }
+
float output_x1,output_y1, output_x2,output_y2;
float canvas_x1,canvas_y1, canvas_x2,canvas_y2;
get_transfers(edl,
output_x1, output_y1, output_x2, output_y2,
canvas_x1, canvas_y1, canvas_x2, canvas_y2);
- int color = get_clear_color();
- window->set_color(color);
if( canvas_y1 > 0 ) {
window->draw_box(0, 0, window_w, canvas_y1);
remove_file(index_filename);
}
+void IndexFile::delete_index_files(Preferences *preferences,
+ Indexable *indexable)
+{
+ delete_index(preferences, indexable, ".toc");
+ delete_index(preferences, indexable, ".idx");
+ delete_index(preferences, indexable, ".mkr");
+}
+
+
int IndexFile::open_file()
{
int result = 0;
int interrupt_index();
static void delete_index(Preferences *preferences,
Indexable *indexable, const char *suffix=0);
+ static void delete_index_files(Preferences *preferences,
+ Indexable *indexable);
static int get_index_filename(char *source_filename,
char *index_directory,
char *index_filename,
// handle command line arguments first
srand(time(0));
ArrayList<char*> filenames;
+ filenames.set_array_delete();
FileSystem fs;
time_t st; time(&st);
if(debug) PRINT_TRACE
}
+void MWindow::update_preferences(Preferences *prefs)
+{
+ if( prefs != preferences )
+ preferences->copy_from(prefs);
+ if( cwindow->playback_engine )
+ cwindow->playback_engine->preferences->copy_from(prefs);
+ for(int i = 0; i < vwindows.size(); i++) {
+ VWindow *vwindow = vwindows[i];
+ if( !vwindow->is_running() ) continue;
+ if( vwindow->playback_engine )
+ vwindow->playback_engine->preferences->copy_from(prefs);
+ }
+ for(int i = 0; i < zwindows.size(); i++) {
+ ZWindow *zwindow = zwindows[i];
+ if( !zwindow->is_running() ) continue;
+ if( zwindow->zgui->playback_engine )
+ zwindow->zgui->playback_engine->preferences->copy_from(prefs);
+ }
+}
+
void MWindow::update_vwindow()
{
for( int i=0; i<vwindows.size(); ++i ) {
//printf("MWindow::rebuild_indices 1 %s\n", indexable->path);
remove_indexfile(indexable);
// Schedule index build
- IndexState *index_state = indexable->index_state;
- index_state->index_status = INDEX_NOTTESTED;
+ indexable->index_state->remove_user();
+ indexable->index_state = new IndexState;
+ IndexFile::delete_index_files(preferences, indexable);
if( indexable->is_asset ) {
Asset *asset = (Asset *)indexable;
if( asset->format != FILE_PCM ) {
}
mainindexes->add_next_asset(0, indexable);
}
+// still in render engine
+ sync_parameters(CHANGE_ALL);
+ awindow->gui->async_update_assets();
mainindexes->start_build();
}
if( vwindow->playback_engine->video_cache )
vwindow->playback_engine->video_cache->delete_entry(asset);
}
+ for(int i = 0; i < zwindows.size(); i++) {
+ ZWindow *zwindow = zwindows[i];
+ if( !zwindow->is_running() ) continue;
+ if( zwindow->zgui->playback_engine->audio_cache )
+ zwindow->zgui->playback_engine->audio_cache->delete_entry(asset);
+ if( zwindow->zgui->playback_engine->video_cache )
+ zwindow->zgui->playback_engine->video_cache->delete_entry(asset);
+ }
}
-
void MWindow::remove_assets_from_project(int push_undo, int redraw, int delete_indexes,
ArrayList<Indexable*> *drag_assets, ArrayList<EDL*> *drag_clips)
{
int overwrite);
// Reset everything for a load
void update_project(int load_mode);
+ void update_preferences(Preferences *prefs);
void update_vwindow();
// Fit selected time to horizontal display range
void fit_selection();
// Not wanted for loading backups.
int update_filename = 1);
-
// Print out plugins which are referenced in the EDL but not loaded.
void test_plugins(EDL *new_edl, char *path);
set_tooltip(ffmpeg_early_probe ? FFMPEG_EARLY_TIP : FFMPEG_LATE_TIP);
mwindow->preferences->set_file_probe_armed("FFMPEG_Early", ffmpeg_early_probe);
mwindow->preferences->set_file_probe_armed("FFMPEG_Late", !ffmpeg_early_probe);
-
+ mwindow->update_preferences(mwindow->preferences);
mwindow->show_warning(&mwindow->preferences->warn_indexes,
_("Changing the base codecs may require rebuilding indexes."));
return 1;
}
mwindow->edl->copy_session(edl, 1);
- mwindow->preferences->copy_from(preferences);
+ mwindow->update_preferences(preferences);
BC_Signals::set_catch_segv(mwindow->preferences->trap_sigsegv);
BC_Signals::set_catch_intr(mwindow->preferences->trap_sigintr);
void Record::delete_index_file(Asset *asset)
{
- IndexFile::delete_index(mwindow->preferences, asset, ".toc");
- IndexFile::delete_index(mwindow->preferences, asset, ".idx");
- IndexFile::delete_index(mwindow->preferences, asset, ".mkr");
+ IndexFile::delete_index_files(mwindow->preferences, asset);
}
void Record::delete_batch()
Resample::Resample()
{
- old = new double[BLACKSIZE];
+ old.allocate(BLACKSIZE, 0);
+ double *old_data = old.get_data();
+ memset(old_data, 0, BLACKSIZE*sizeof(*old_data));
resample_init = 0;
last_ratio = 0;
output_temp = 0;
Resample::~Resample()
{
- delete [] old;
delete [] output_temp;
delete input;
}
-int Resample::read_samples(Samples *buffer, int64_t start, int64_t len)
+int Resample::read_samples(Samples *buffer, int64_t start, int64_t len, int direction)
{
return 0;
}
-int Resample::get_direction()
-{
- return direction;
-}
-
-
void Resample::reset()
{
resample_init = 0;
input_position = 0;
}
-double Resample::blackman(int i, double offset, double fcn, int l)
+void Resample::blackman(double fcn, int filter_l)
{
- /* This algorithm from:
-SIGNAL PROCESSING ALGORITHMS IN FORTRAN AND C
-S.D. Stearns and R.A. David, Prentice-Hall, 1992
- */
-
- double bkwn;
- double wcn = (M_PI * fcn);
- double dly = l / 2.0;
- double x = i-offset;
- if(x < 0) x = 0;
- else
- if(x > l) x = l;
-
- bkwn = 0.42 - 0.5 * cos((x * 2) * M_PI /l) + 0.08 * cos((x * 4) * M_PI /l);
- if(fabs(x - dly) < 1e-9)
- return wcn / M_PI;
- else
- return (sin((wcn * (x - dly))) / (M_PI * (x - dly)) * bkwn);
+ double wcn = M_PI * fcn;
+ double ctr = filter_l / 2.0;
+ double cir = 2*M_PI/filter_l;
+ for( int j=0; j<=2*BPC; ++j ) {
+ double offset = (j-BPC) / (2.*BPC); // -0.5 ... 0.5
+ for( int i=0; i<=filter_l; ++i ) {
+ double x = i - offset;
+ bclamp(x, 0,filter_l);
+ double v, dx = x - ctr;
+ if( fabs(dx) >= 1e-9 ) {
+ double curve = sin(wcn * dx) / (M_PI * dx);
+ double th = x * cir;
+ double blkmn = 0.42 - 0.5 * cos(th) + 0.08 * cos(2*th);
+ v = blkmn * curve;
+ }
+ else
+ v = fcn;
+ blackfilt[j][i] = v;
+ }
+ }
}
// {
// memcpy(output, output_temp, size * sizeof(double));
// // Shift leftover forward
-// for(int i = size; i < output_size; i++)
+// for( int i = size; i < output_size; i++ )
// output_temp[i - size] = output_temp[i];
// output_size -= size;
// }
+// starts odd = (even-1)
+#define FILTER_N (BLACKSIZE-6)
+#define FILTER_L (FILTER_N - (~FILTER_N & 1));
-void Resample::resample_chunk(Samples *input_buffer,
- int64_t in_len,
- int in_rate,
- int out_rate)
+void Resample::resample_chunk(Samples *input_buffer, int64_t in_len,
+ int in_rate, int out_rate)
{
- double resample_ratio = (double)in_rate / out_rate;
- int filter_l;
- double fcn, intratio;
- double offset, xvalue;
- int num_used;
- int i, j, k;
- double *input = input_buffer->get_data();
//printf("Resample::resample_chunk %d in_len=%jd input_size=%d\n",
// __LINE__, in_len, input_size);
-
- intratio = (fabs(resample_ratio - floor(.5 + resample_ratio)) < .0001);
- fcn = .90 / resample_ratio;
- if(fcn > .90) fcn = .90;
- filter_l = BLACKSIZE - 6;
-/* must be odd */
- if(0 == filter_l % 2 ) --filter_l;
-
-/* if resample_ratio = int, filter_l should be even */
- filter_l += (int)intratio;
-
+ double *input = input_buffer->get_data();
+ double resample_ratio = (double)in_rate / out_rate;
+ double fcn = .90 / resample_ratio;
+ if( fcn > .90 ) fcn = .90;
+ int filter_l = FILTER_L;
+// if resample_ratio = int, filter_l should include right edge
+ if( fabs(resample_ratio - floor(.5 + resample_ratio)) < .0001 )
+ ++filter_l;
// Blackman filter initialization must be called whenever there is a
// sampling ratio change
- if(!resample_init || last_ratio != resample_ratio)
- {
+ if( !resample_init || last_ratio != resample_ratio ) {
resample_init = 1;
+ last_ratio = resample_ratio;
+ blackman(fcn, filter_l);
itime = 0;
- bzero(old, sizeof(double) * BLACKSIZE);
+ }
-// precompute blackman filter coefficients
- for (j = 0; j <= 2 * BPC; ++j)
- {
- for(j = 0; j <= 2 * BPC; j++)
- {
- offset = (double)(j - BPC) / (2 * BPC);
- for(i = 0; i <= filter_l; i++)
- {
- blackfilt[j][i] = blackman(i, offset, fcn, filter_l);
- }
- }
+ double filter_l2 = filter_l/2.;
+ int l2 = filter_l2;
+ int64_t end_time = itime + in_len + l2;
+ int64_t out_time = end_time / resample_ratio + 1;
+ int64_t demand = out_time - output_position;
+ if( demand >= output_allocation ) {
+// demand 2**n buffer
+ int64_t new_allocation = output_allocation ? output_allocation : 16384;
+ while( new_allocation < demand ) new_allocation <<= 1;
+ double *new_output = new double[new_allocation];
+ if( output_temp ) {
+ memmove(new_output, output_temp, output_allocation*sizeof(double));
+ delete [] output_temp;
}
+ output_temp = new_output;
+ output_allocation = new_allocation;
}
// Main loop
- double *inbuf_old = old;
- for(k = 0; 1; k++)
- {
- double time0;
- int joff;
-
- time0 = k * resample_ratio;
- j = (int)floor(time0 - itime);
-
-// if(j + filter_l / 2 >= input_size) break;
- if(j + filter_l / 2 >= in_len) break;
-
-/* blackman filter. by default, window centered at j+.5(filter_l%2) */
-/* but we want a window centered at time0. */
- offset = (time0 - itime - (j + .5 * (filter_l % 2)));
- joff = (int)floor((offset * 2 * BPC) + BPC + .5);
- xvalue = 0;
-
-
- for(i = 0; i <= filter_l; i++)
- {
- int j2 = i + j - filter_l / 2;
-//printf("j2=%d\n", j2);
- double y = ((j2 < 0) ? inbuf_old[BLACKSIZE + j2] : input[j2]);
-
- xvalue += y * blackfilt[joff][i];
- }
-
-
- if(output_allocation <= output_size)
- {
- double *new_output = 0;
- int64_t new_allocation = output_allocation ? (output_allocation * 2) : 16384;
- new_output = new double[new_allocation];
- if(output_temp)
- {
- bcopy(output_temp, new_output, output_allocation * sizeof(double));
- delete [] output_temp;
- }
-
- output_temp = new_output;
- output_allocation = new_allocation;
- }
-
+ double *old_data = old.get_data();
+ double ctr_pos = 0;
+ int otime = 0, last_used = 0;
+ while( output_size < output_allocation ) {
+ double in_pos = otime * resample_ratio;
+// window centered at ctr_pos
+ ctr_pos = in_pos + itime;
+ double pos = ctr_pos - filter_l2;
+ int ipos = floor(pos);
+ last_used = ipos + filter_l;
+ if( last_used >= in_len ) break;
+ double fraction = pos - ipos;
+ int phase = floor(fraction * 2*BPC + .5);
+ int i = ipos, j = filter_l; // fir filter
+ double xvalue = 0, *filt = blackfilt[phase];
+ for( ; j>=0 && i<0; ++i,--j ) xvalue += *filt++ * old_data[BLACKSIZE + i];
+ for( ; j>=0; ++i,--j ) xvalue += *filt++ * input[i];
output_temp[output_size++] = xvalue;
+ ++otime;
}
-
- num_used = MIN(in_len, j + filter_l / 2);
- itime += num_used - k * resample_ratio;
- for(i = 0; i < BLACKSIZE; i++)
- inbuf_old[i] = input[num_used + i - BLACKSIZE];
-
- last_ratio = resample_ratio;
-
-}
-
-int Resample::read_chunk(Samples *input,
- int64_t len)
-{
- int fragment = len;
- if(direction == PLAY_REVERSE &&
- input_position - len < 0)
- {
- fragment = input_position;
- }
-
- int result = read_samples(input, input_position, fragment);
-
- if(direction == PLAY_FORWARD)
- {
- input_position += fragment;
- }
- else
- {
- input_position -= fragment;
-// Mute unused part of buffer
- if(fragment < len)
- {
- bzero(input->get_data() + fragment,
- (len - fragment) * sizeof(double));
- }
- }
-
- return result;
+// move ctr_pos backward by in_len as new itime offset
+// the next read will be in the history, itime is negative
+ itime = ctr_pos - in_len;
+ memmove(old_data, input+in_len-BLACKSIZE, BLACKSIZE*sizeof(double));
}
-
void Resample::reverse_buffer(double *buffer, int64_t len)
{
double *ap = buffer;
}
}
+int Resample::set_input_position(int64_t in_pos, int in_dir)
+{
+ reset();
+ input_position = in_pos;
+ direction = in_dir;
+// update old, just before/after input going fwd/rev;
+ int dir = direction == PLAY_FORWARD ? -1 : 1;
+ in_pos += dir * BLACKSIZE;
+ return read_samples(&old, in_pos, BLACKSIZE, in_dir);
+}
-int Resample::resample(Samples *output,
- int64_t out_len,
- int in_rate,
- int out_rate,
- int64_t out_position,
- int direction)
+int Resample::resample(Samples *output, int64_t out_len,
+ int in_rate, int out_rate, int64_t out_position, int direction)
{
int result = 0;
-
-
-//printf("Resample::resample 1 output_position=%jd out_position=%jd out_len=%jd\n",
-// output_position, out_position, out_len);
-// Changed position
- if(labs(this->output_position - out_position) > 0 ||
- direction != this->direction)
- {
- reset();
-
-// Compute starting point in input rate.
- this->input_position = out_position * in_rate / out_rate;
- this->direction = direction;
+ if( this->output_position != out_position ||
+ this->direction != direction ) {
+//printf("missed %jd!=%jd\n", output_position, out_position);
+// starting point in input rate.
+ int64_t in_pos = out_position * in_rate / out_rate;
+ set_input_position(in_pos, direction);
}
+//else
+//printf("matched %jd==%jd\n", output_position, out_position);
-
+ int dir = direction == PLAY_REVERSE ? -1 : 1;
int remaining_len = out_len;
double *output_ptr = output->get_data();
- while(remaining_len > 0 && !result)
- {
-// Drain output buffer
- if(output_size)
- {
- int fragment_len = output_size;
- if(fragment_len > remaining_len) fragment_len = remaining_len;
-
-//printf("Resample::resample 1 %d %d\n", remaining_len, output_size);
- bcopy(output_temp, output_ptr, fragment_len * sizeof(double));
-
-// Shift leftover forward
- for(int i = fragment_len; i < output_size; i++)
- output_temp[i - fragment_len] = output_temp[i];
-
- output_size -= fragment_len;
- remaining_len -= fragment_len;
- output_ptr += fragment_len;
+ while( remaining_len > 0 && !result ) {
+ if( output_size ) {
+ int len = bmin(output_size, remaining_len);
+ memmove(output_ptr, output_temp, len*sizeof(double));
+ memmove(output_temp, output_temp+len, (output_size-=len)*sizeof(double));
+ output_ptr += len; remaining_len -= len;
}
-
-// Import new samples
-//printf("Resample::resample 2 %d\n", remaining_len);
- if(remaining_len > 0)
- {
-//printf("Resample::resample 3 input_size=%d out_position=%d\n", input_size, out_position);
- result = read_chunk(input, input_size);
- resample_chunk(input,
- input_size,
- in_rate,
- out_rate);
+ if( remaining_len > 0 ) {
+ result = read_samples(input, input_position, input_size, direction);
+ if( result ) break;
+ resample_chunk(input, input_size, in_rate, out_rate);
+ input_position += dir * input_size;
}
}
-
-
- if(direction == PLAY_FORWARD)
- this->output_position = out_position + out_len;
- else
- this->output_position = out_position - out_len;
-
-//printf("Resample::resample 2 %d %d\n", this->output_position, out_position);
-//printf("Resample::resample 2 %d %d\n", out_len, output_size);
-
-//printf("Resample::resample 2 %d\n", output_size);
+ if( !result )
+ this->output_position = out_position + dir * out_len;
return result;
}
#define BLACKSIZE 25
#include "resample.inc"
-#include "samples.inc"
+#include "samples.h"
#include <stdint.h>
class Resample
// All positions are in file sample rate
// This must reverse the buffer during reverse playback
// so the filter always renders forward.
- virtual int read_samples(Samples *buffer, int64_t start, int64_t len);
+ virtual int read_samples(Samples *buffer,
+ int64_t start, int64_t len, int direction);
// Resample from the file handler and store in *output.
// Returns 1 if the input reader failed.
- int resample(Samples *samples,
- int64_t out_len,
- int in_rate,
- int out_rate,
// Starting sample in output samplerate
// If reverse, the end of the buffer.
- int64_t out_position,
- int direction);
-
- int get_direction();
-
+ int resample(Samples *samples,
+ int64_t out_len, int in_rate, int out_rate,
+ int64_t out_position, int direction);
static void reverse_buffer(double *buffer, int64_t len);
// Reset after seeking
void reset();
private:
- double blackman(int i, double offset, double fcn, int l);
+ void blackman(double fcn, int l);
+ int set_input_position(int64_t in_pos, int in_dir);
// Query output temp
int get_output_size();
// void read_output(Samples *output, int size);
// Resamples input and dumps it to output_temp
- void resample_chunk(Samples *input,
- int64_t in_len,
- int in_rate,
- int out_rate);
- int read_chunk(Samples *input,
- int64_t len);
-
-// History buffer for resampling.
- double *old;
- double itime;
-
-
+ void resample_chunk(Samples *input, int64_t in_len,
+ int in_rate, int out_rate);
+ int direction;
// Unaligned resampled output
double *output_temp;
-
-
// Total samples in unaligned output
int64_t output_size;
-
- int direction;
// Allocation of unaligned output
int64_t output_allocation;
+// History buffer for resampling.
+ Samples old;
// input chunk
Samples *input;
+ double itime;
// Position of source in source sample rate.
int64_t input_position;
int64_t input_size;
for( int i=0; i<audio_channels; ++i )
audio_out_packed[i] = arender->audio_out[i]->get_data();
+// Time stretch the fragment to the real_output size
for( int i=0; i<audio_channels; ++i ) {
double *current_buffer = audio_out_packed[i];
-// Time stretch the fragment to the real_output size
- if( speed > 1 ) {
- int out = 0;
- for( int in=0; in<len; ) {
-// samples in real output buffer for each to sample rendered.
- int end = (out+1) * speed;
- if( end > len ) end = len;
- int k = end - in;
- double sample = 0;
- while( in < end ) sample += current_buffer[in++];
- if( k > 0 ) sample /= k;
+ if( speed > 1 ) { // buffer gets shorter
+ int in = 0, out = 0;
+ while( in < len ) {
+ int next = (out+1) * speed;
+ if( next > len) next = len;
+ double sample = current_buffer[in];
+ for( int i=in; ++i<next; ) sample += current_buffer[i];
+ int l = next - in;
+ if( l > 1 ) sample /= l;
current_buffer[out++] = sample;
+ in = next;
}
real_output_len = out;
}
- else if( speed < 1 ) {
- int end = len / speed;
- real_output_len = end;
- for( int in=len, out=end; --in>=0; ) {
-// samples rendered in real output buffer sample.
- int start = in / speed;
- double v = current_buffer[in];
- while( --out >= start ) current_buffer[out] = v;
+ else if( speed < 1 ) { // buffer gets longer
+ real_output_len = len / speed;
+ int in = len, out = real_output_len;
+ while( in > 0 && out > 0 ) {
+ double sample = current_buffer[--in];
+ int next = in / speed;
+ while( out > next ) current_buffer[--out] = sample;
}
}
else
#include "edl.inc"
#include "filexml.inc"
#include "mwindow.inc"
-#include "playbackengine.inc"
#include "renderengine.inc"
#include "zwindowgui.inc"
-med422p10.pro
+prores.pro
// tell/eof %jd/%d\n", output_position, output_size, aud_pos, end_pos,
// demand, demux->tell_byte(), demux->eof());
if( demux->eof() ) break;
+ int needed_history = len > AUDIO_HISTORY ? len : AUDIO_HISTORY;
/* if overflowing, shift audio back */
- if( src->seekable && output_size > AUDIO_HISTORY ) {
- int diff = demand + output_size - AUDIO_HISTORY;
+ if( src->seekable && output_size > needed_history ) {
+ int diff = demand + output_size - needed_history;
shift_audio(diff);
}
int samples = read_frame(1);
j = track->track_position() - output_position;
k = output_size - j;
if( k > len ) k = len;
- float *out = channel < output_channels ?
+ float *out = j >= 0 && channel < output_channels ?
output[channel] + j : 0;
/* transmit data in specified format */