rework audio import_samples + resample + playback speed sampling, fix clear_boarder...
authorGood Guy <[email protected]>
Thu, 28 Nov 2019 20:19:55 +0000 (13:19 -0700)
committerGood Guy <[email protected]>
Thu, 28 Nov 2019 20:19:55 +0000 (13:19 -0700)
17 files changed:
cinelerra-5.1/cinelerra/amodule.C
cinelerra-5.1/cinelerra/amodule.h
cinelerra-5.1/cinelerra/canvas.C
cinelerra-5.1/cinelerra/indexfile.C
cinelerra-5.1/cinelerra/indexfile.h
cinelerra-5.1/cinelerra/main.C
cinelerra-5.1/cinelerra/mwindow.C
cinelerra-5.1/cinelerra/mwindow.h
cinelerra-5.1/cinelerra/mwindowgui.C
cinelerra-5.1/cinelerra/preferencesthread.C
cinelerra-5.1/cinelerra/record.C
cinelerra-5.1/cinelerra/resample.C
cinelerra-5.1/cinelerra/resample.h
cinelerra-5.1/cinelerra/virtualaconsole.C
cinelerra-5.1/cinelerra/zwindow.h
cinelerra-5.1/ffmpeg/video/pro.dfl
cinelerra-5.1/libzmpeg3/audio/audio.C

index 50b58884784a42b882c425ae913f846745195eae..9e2c59b6840a0ea98559c95813ec9818ff78fc16 100644 (file)
@@ -72,75 +72,12 @@ AModuleResample::~AModuleResample()
                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,
@@ -148,6 +85,7 @@ AModule::AModule(RenderEngine *renderengine,
  : 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);
@@ -171,6 +109,52 @@ AModule::~AModule()
        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);
@@ -206,258 +190,179 @@ CICache* AModule::get_cache()
 
 
 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;
 }
 
@@ -704,10 +609,7 @@ if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
                                }
                        }
 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)
                        {
index 1d17bf0f63d85d367f5bf4b356bc550cf0ca294a..128b280848e9f34378f1d7e1955e019671dd3872 100644 (file)
@@ -55,7 +55,8 @@ public:
        ~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
@@ -77,21 +78,13 @@ public:
        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);
index 93507c3e557a08d897122a27f9994874d028ccfb..410145f04817c079fb53f7aa7bb8b8032ca79e94 100644 (file)
@@ -767,16 +767,22 @@ void Canvas::clear_borders(EDL *edl)
 {
        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);
index 3e1ce389fa7ae911af92717c78f18e5aefd9982d..3c6fd97f742e735d3941d9a0e775e52682e26d41 100644 (file)
@@ -232,6 +232,15 @@ void IndexFile::delete_index(Preferences *preferences,
        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;
index dd38e9b84e75872912a1f5a24b301b74ad24441d..6320463155c235a93bd1e3b685a904e0c4950ac8 100644 (file)
@@ -60,6 +60,8 @@ public:
        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,
index 6e0b6d5e7422a3027b107139ef71e8dd52bf692c..4b04a11b2f6347b17a08831a6a19d822d12916f0 100644 (file)
@@ -145,6 +145,7 @@ int main(int argc, char *argv[])
 // handle command line arguments first
        srand(time(0));
        ArrayList<char*> filenames;
+       filenames.set_array_delete();
        FileSystem fs;
 
        time_t st; time(&st);
index 89d188debcece611b4a3d8a4a017e665aa97d324..03e265e6b75525023afea2276c49852e1ce2c89d 100644 (file)
@@ -3688,6 +3688,26 @@ void MWindow::update_project(int load_mode)
        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 ) {
@@ -3718,8 +3738,9 @@ void MWindow::rebuild_indices()
 //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 ) {
@@ -3733,6 +3754,9 @@ void MWindow::rebuild_indices()
                }
                mainindexes->add_next_asset(0, indexable);
        }
+// still in render engine
+       sync_parameters(CHANGE_ALL);
+       awindow->gui->async_update_assets();
        mainindexes->start_build();
 }
 
@@ -4078,9 +4102,16 @@ void MWindow::remove_asset_from_caches(Asset *asset)
                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)
 {
index 0e6db95ec52ee2dd6489cc674838e20284e451dc..513e1bfe3529eb1e918188af279e5188e1d63409 100644 (file)
@@ -181,6 +181,7 @@ public:
                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();
@@ -231,7 +232,6 @@ public:
 // 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);
 
index 2350f92e96c6a37c49f757f57875839f7de9ba8d..248a56004a9d4b3f0297238583143a8b2ccbe845 100644 (file)
@@ -2291,7 +2291,7 @@ int FFMpegToggle::handle_event()
        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;
index b085e13be2eee6c69612b32525afe8a4c21f9331..e4f050be1d2ff4b7919ca8106e5a0eeb0a32e9f1 100644 (file)
@@ -252,7 +252,7 @@ int PreferencesThread::apply_settings()
        }
 
        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);
index 4b8accd38ab0cc1b59779e671a5899c479240158..2dd9e2c5e60ae55df8a7936d0509a05847e73262 100644 (file)
@@ -474,9 +474,7 @@ void Record::activate_batch(int number)
 
 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()
index 9e51a994b485ebab0486d51ee8aa9586373a8880..8ebd90dc57c725df9329616bfd6e98bf03040b93 100644 (file)
@@ -34,7 +34,9 @@
 
 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;
@@ -51,22 +53,15 @@ Resample::Resample()
 
 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;
@@ -75,26 +70,28 @@ void Resample::reset()
        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;
+               }
+       }
 }
 
 
@@ -107,148 +104,83 @@ int Resample::get_output_size()
 // {
 //     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;
@@ -260,76 +192,50 @@ void Resample::reverse_buffer(double *buffer, int64_t len)
        }
 }
 
+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;
 }
 
index b80bb6bd933304d59c79effad28fc250b7002c51..d58e1e52fe01156454e62c305284f091e8e08c85 100644 (file)
@@ -29,7 +29,7 @@
 #define BLACKSIZE 25
 
 #include "resample.inc"
-#include "samples.inc"
+#include "samples.h"
 #include <stdint.h>
 
 class Resample
@@ -41,57 +41,43 @@ public:
 // 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;
index 4afc12f7f7b1d822b445a5be7984f2ce37ce2ed4..fab1b6a7599338b00aad8e2664947b2fdab2c680 100644 (file)
@@ -205,31 +205,30 @@ if(debug) printf("VirtualAConsole::process_buffer %d\n", __LINE__);
                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
index 3019d438c875b8f64687d9dfe91726c3e1e7c114..fcd05699c1f7c45084474a75f378844f6860a00f 100644 (file)
@@ -28,7 +28,6 @@
 #include "edl.inc"
 #include "filexml.inc"
 #include "mwindow.inc"
-#include "playbackengine.inc"
 #include "renderengine.inc"
 #include "zwindowgui.inc"
 
index b317d6b694b060fb17e11fdda498f7e4e1ce1523..f1137e2f8fa3eca7790b652175cdd65a6de6f4f5 100644 (file)
@@ -1 +1 @@
-med422p10.pro
+prores.pro
index 4a98bbf431c54f2e10b5fe12f55df4b0a99bc60a..5d88c169ad88cb443d0587f16db1a1e0d860045a 100644 (file)
@@ -720,9 +720,10 @@ decode_audio(void *output_v, int atyp, int channel, int len)
 //  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);
@@ -742,7 +743,7 @@ decode_audio(void *output_v, int atyp, int channel, int len)
   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 */