no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / indexfile.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "arender.h"
23 #include "asset.h"
24 #include "automation.h"
25 #include "autos.h"
26 #include "bcsignals.h"
27 #include "bctimer.h"
28 #include "cache.h"
29 #include "clip.h"
30 #include "condition.h"
31 #include "edit.h"
32 #include "edl.h"
33 #include "edlsession.h"
34 #include "errorbox.h"
35 #include "file.h"
36 #include "filesystem.h"
37 #include "filexml.h"
38 #include "floatauto.h"
39 #include "floatautos.h"
40 #include "indexable.h"
41 #include "indexfile.h"
42 #include "indexstate.h"
43 #include "indexthread.h"
44 #include "language.h"
45 #include "localsession.h"
46 #include "mainprogress.h"
47 #include "mwindowgui.h"
48 #include "mwindow.h"
49 #include "preferences.h"
50 #include "removefile.h"
51 #include "renderengine.h"
52 #include "resourcepixmap.h"
53 #include "samples.h"
54 #include "theme.h"
55 #include "timelinepane.h"
56 #include "trackcanvas.h"
57 #include "tracks.h"
58 #include "transportque.h"
59 #include "vframe.h"
60
61
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <stdint.h>
65 #include <unistd.h>
66 #include <string.h>
67 #include <errno.h>
68 #include <fcntl.h>
69 #include <ctype.h>
70
71 #include <sys/types.h>
72 #include <sys/stat.h>
73 #ifdef HAVE_ISOFS
74 #include <linux/iso_fs.h>
75 #endif
76
77 // check for isofs volume_id for dvd/cdrom
78
79 static int udf_volume_id(const char *path, char *fname)
80 {
81         int result = 1;
82 #ifdef HAVE_ISOFS
83         struct stat st;
84         if( stat(path,&st) ) return 1;
85         // search mounted devices
86         FILE *fp = fopen("/proc/mounts","r");
87         if( !fp ) return 1;
88
89         while( result && !feof(fp) && !ferror(fp) ) {
90                 char devpath[BCTEXTLEN], mpath[BCTEXTLEN];
91                 char options[BCTEXTLEN], line[BCTEXTLEN];
92                 char fstype[64], zero1[16], zero2[16];
93                 if( !fgets(&line[0], sizeof(line)-1, fp) ) break;
94                 int n = sscanf(&line[0], "%s %s %s %s %s %s\n",
95                          devpath, mpath, fstype, options, zero1, zero2);
96                 if( n != 6 ) continue;
97                 // check udf filesystems
98                 if( strcmp(fstype,"udf") != 0 ) continue;
99                 struct stat dst;
100                 if( stat(devpath,&dst) ) continue;
101                 if( st.st_dev != dst.st_rdev ) continue;
102                 int fd = open(devpath,O_RDONLY);
103                 if( fd < 0 ) continue;
104                 struct iso_primary_descriptor id;
105                 if( lseek(fd,0x8000,SEEK_SET) == 0x8000 )
106                         n = read(fd,&id,sizeof(id));
107                 close(fd);
108                 if( n != sizeof(id) ) continue;
109                 // look for magic number
110                 if( strncmp(ISO_STANDARD_ID,id.id,sizeof(id.id)) ) continue;
111                 // look for volume_id
112                 if( !isalnum(id.volume_id[0]) ) continue;
113                 char *bp = (char*)&id.volume_id[0], *cp = fname;
114                 for( int i=0; i<(int)sizeof(id.volume_id); ++i ) *cp++ = *bp++;
115                 while( --cp>=fname && *cp==' ' ) *cp = 0;
116                 if( !*fname ) continue;
117                 // fname = volume_id _ creation_date
118                 ++cp;  *cp++ = '_';  bp = (char*)&id.creation_date[0];
119                 for( int i=0; i<(int)sizeof(id.creation_date)-1; ++i ) {
120                         if( !isdigit(*bp) ) break;
121                         *cp++ = *bp++;
122                 }
123                 *cp++ = 0;
124                 if( cp-fname > 4 ) result = 0;
125         }
126
127         fclose(fp);
128 #endif
129         return result;
130 }
131
132 // Use native sampling rates for files so the same index can be used in
133 // multiple projects.
134
135 IndexFile::IndexFile(MWindow *mwindow)
136 {
137 //printf("IndexFile::IndexFile 1\n");
138         reset();
139         this->mwindow = mwindow;
140 //printf("IndexFile::IndexFile 2\n");
141         redraw_timer = new Timer;
142 }
143
144 IndexFile::IndexFile(MWindow *mwindow,
145         Indexable *indexable)
146 {
147 //printf("IndexFile::IndexFile 2\n");
148         reset();
149         this->mwindow = mwindow;
150         this->indexable = indexable;
151         redraw_timer = new Timer;
152         if(indexable)
153         {
154                 indexable->add_user();
155                 source_channels = indexable->get_audio_channels();
156                 source_samplerate = indexable->get_sample_rate();
157                 source_length = indexable->get_audio_samples();
158         }
159 }
160
161 IndexFile::~IndexFile()
162 {
163 //printf("IndexFile::~IndexFile 1\n");
164         delete redraw_timer;
165         if(indexable) indexable->remove_user();
166         close_source();
167 }
168
169 void IndexFile::reset()
170 {
171         fd = 0;
172         source = 0;
173         interrupt_flag = 0;
174         source_length = 0;
175         source_channels = 0;
176         indexable = 0;
177         render_engine = 0;
178         cache = 0;
179 }
180
181 IndexState* IndexFile::get_state()
182 {
183         IndexState *index_state = 0;
184         if(indexable) index_state = indexable->index_state;
185         return index_state;
186 }
187
188
189
190 int IndexFile::open_index()
191 {
192         IndexState *index_state = 0;
193         int result = 0;
194
195 // use buffer if being built
196         index_state = get_state();
197
198         if(index_state->index_status == INDEX_BUILDING)
199         {
200 // use buffer
201                 result = 0;
202         }
203         else
204         if(!(result = open_file()))
205         {
206 // opened existing file
207                 if(read_info())
208                 {
209                         result = 1;
210                         close_index();
211                 }
212                 else
213                 {
214                         index_state->index_status = INDEX_READY;
215                 }
216         }
217         else
218         {
219                 result = 1;
220         }
221
222         return result;
223 }
224
225 void IndexFile::delete_index(Preferences *preferences,
226         Indexable *indexable, const char *suffix)
227 {
228         char index_filename[BCTEXTLEN];
229         char source_filename[BCTEXTLEN];
230         const char *path = indexable->path;
231         if( !*path ) return;
232         get_index_filename(source_filename,
233                 preferences->index_directory,
234                 index_filename, path, suffix);
235 //printf("IndexFile::delete_index %s %s\n", source_filename, index_filename);
236         remove_file(index_filename);
237 }
238
239 void IndexFile::delete_index_files(Preferences *preferences,
240         Indexable *indexable)
241 {
242         delete_index(preferences, indexable, ".toc");
243         delete_index(preferences, indexable, ".idx");
244         delete_index(preferences, indexable, ".mkr");
245 }
246
247
248 int IndexFile::open_file()
249 {
250         int result = 0;
251         const int debug = 0;
252         const char *path = indexable->path;
253
254
255 //printf("IndexFile::open_file %f\n", indexable->get_frame_rate());
256
257         get_index_filename(source_filename,
258                 mwindow->preferences->index_directory,
259                 index_filename,
260                 path);
261
262         if(debug) printf("IndexFile::open_file %d index_filename=%s\n",
263                 __LINE__,
264                 index_filename);
265         fd = fopen(index_filename, "rb");
266         if( fd != 0 )
267         {
268 // Index file already exists.
269 // Get its last size without changing the real asset status.
270                 Indexable *test_indexable = new Indexable(0);
271                 if(indexable)
272                         test_indexable->copy_indexable(indexable);
273                 read_info(test_indexable);
274                 IndexState *index_state = test_indexable->index_state;
275
276                 FileSystem fs;
277                 if(fs.get_date(index_filename) < fs.get_date(test_indexable->path))
278                 {
279                         if(debug) printf("IndexFile::open_file %d index_date=%jd source_date=%jd\n",
280                                 __LINE__,
281                                 fs.get_date(index_filename),
282                                 fs.get_date(test_indexable->path));
283
284 // index older than source
285                         result = 2;
286                         fclose(fd);
287                         fd = 0;
288                 }
289                 else
290                 if(fs.get_size(test_indexable->path) != index_state->index_bytes)
291                 {
292 // source file is a different size than index source file
293                         if(debug) printf("IndexFile::open_file %d index_size=%jd source_size=%jd\n",
294                                 __LINE__,
295                                 index_state->index_bytes,
296                                 fs.get_size(test_indexable->path));
297                         result = 2;
298                         fclose(fd);
299                         fd = 0;
300                 }
301                 else
302                 {
303                         if(debug) printf("IndexFile::open_file %d\n",
304                                 __LINE__);
305                         fseek(fd, 0, SEEK_END);
306                         file_length = ftell(fd);
307                         fseek(fd, 0, SEEK_SET);
308                         result = 0;
309                 }
310                 test_indexable->Garbage::remove_user();
311         }
312         else
313         {
314 // doesn't exist
315                 if(debug) printf("IndexFile::open_file %d index_filename=%s doesn't exist\n",
316                         __LINE__,
317                         index_filename);
318                 result = 1;
319         }
320
321         return result;
322 }
323
324 int IndexFile::open_source()
325 {
326 //printf("IndexFile::open_source %p %s\n", asset, asset->path);
327         int result = 0;
328         if(indexable && indexable->is_asset)
329         {
330                 if(!source) source = new File;
331
332                 Asset *asset = (Asset*)indexable;
333                 if(source->open_file(mwindow->preferences,
334                         asset, 1, 0))
335                 {
336                         //printf("IndexFile::open_source() Couldn't open %s.\n", asset->path);
337                         result = 1;
338                 }
339                 else
340                 {
341                         FileSystem fs;
342                         asset->index_state->index_bytes = fs.get_size(asset->path);
343                         source_length = source->get_audio_length();
344                         int proxy_scale = asset->proxy_scale;
345                         if( proxy_scale > 0 ) {
346                                 asset->width = asset->actual_width * proxy_scale;
347                                 asset->height = asset->actual_height * proxy_scale;
348                         }
349                 }
350         }
351         else
352         {
353                 TransportCommand command;
354                 command.command = NORMAL_FWD;
355                 command.get_edl()->copy_all((EDL*)indexable);
356                 command.change_type = CHANGE_ALL;
357                 command.realtime = 0;
358                 cache = new CICache(mwindow->preferences);
359                 render_engine = new RenderEngine(0,
360                         mwindow->preferences, 0, 0);
361                 render_engine->set_acache(cache);
362                 render_engine->arm_command(&command);
363                 FileSystem fs;
364                 indexable->index_state->index_bytes = fs.get_size(indexable->path);
365         }
366
367         return result;
368 }
369
370 void IndexFile::close_source()
371 {
372         delete source;
373         source = 0;
374
375         delete render_engine;
376         render_engine = 0;
377         if( cache ) {
378                 cache->remove_user();
379                 cache = 0;
380         }
381 }
382
383 int64_t IndexFile::get_required_scale()
384 {
385         int64_t result = 1;
386
387
388 // get scale of index file
389 // Total peaks which may be stored in buffer
390         int64_t peak_count = mwindow->preferences->index_size /
391                 (2 * sizeof(float) * source_channels);
392         for(result = 1;
393                 source_length / result > peak_count;
394                 result *= 2)
395                 ;
396
397 // Takes too long to draw from source on a CDROM.  Make indexes for
398 // everything.
399
400         return result;
401 }
402
403 int IndexFile::get_index_filename(char *source_filename,
404         char *index_directory,
405         char *index_filename,
406         const char *input_filename,
407         const char *suffix)
408 {
409         const char *input_fn = input_filename;
410         char volume_id[BCTEXTLEN];
411 // Replace mount/directory with volume_id if isofs
412         if( !udf_volume_id(input_filename, volume_id) )
413         {
414                 char *cp = strrchr((char*)input_filename,'/');
415                 if( cp ) input_fn = cp + 1;
416                 for( cp=volume_id; *cp; ++cp );
417                 *cp++ = '_';  strcpy(cp, input_fn);
418                 input_fn = volume_id;
419         }
420 // Replace slashes and dots
421         int i, j;
422         int len = strlen(input_fn);
423         for(i = 0, j = 0; i < len; i++)
424         {
425                 if(input_fn[i] != '/' &&
426                         input_fn[i] != '.')
427                         source_filename[j++] = input_fn[i];
428                 else
429                 {
430                         if(i > 0)
431                                 source_filename[j++] = '_';
432                 }
433         }
434         source_filename[j] = 0;
435         FileSystem fs;
436         fs.join_names(index_filename, index_directory, source_filename);
437         strcat(index_filename, suffix ? suffix : ".idx");
438         return 0;
439 }
440
441 int IndexFile::interrupt_index()
442 {
443         interrupt_flag = 1;
444         return 0;
445 }
446
447 // Read data into buffers
448
449 int IndexFile::create_index(MainProgressBar *progress)
450 {
451         int result = 0;
452 SET_TRACE
453
454         interrupt_flag = 0;
455
456 // open the source file
457         if(open_source()) return 1;
458         source_channels = indexable->get_audio_channels();
459         source_samplerate = indexable->get_sample_rate();
460         source_length = indexable->get_audio_samples();
461
462 SET_TRACE
463
464         get_index_filename(source_filename,
465                 mwindow->preferences->index_directory,
466                 index_filename,
467                 indexable->path);
468
469 SET_TRACE
470
471 // Some file formats have their own sample index.
472 // Test for index in stream table of contents
473         if(source && !source->get_index(this, progress))
474         {
475                 IndexState *index_state = get_state();
476                 index_state->index_status = INDEX_READY;
477                 redraw_edits(1);
478         }
479         else
480 // Build index from scratch
481         {
482 SET_TRACE
483
484 // Indexes are now built for everything since it takes too long to draw
485 // from CDROM source.
486
487 // get amount to read at a time in floats
488                 int64_t buffersize = 65536;
489                 char string[BCTEXTLEN];
490                 sprintf(string, _("Creating %s."), index_filename);
491
492                 progress->update_title(string);
493                 progress->update_length(source_length);
494                 redraw_timer->update();
495 SET_TRACE
496
497 // thread out index thread
498                 IndexThread *index_thread = new IndexThread(mwindow,
499                         this,
500                         index_filename,
501                         buffersize,
502                         source_length);
503                 index_thread->start_build();
504
505 // current sample in source file
506                 int64_t position = 0;
507                 int64_t fragment_size = buffersize;
508                 int current_buffer = 0;
509
510
511 // pass through file once
512 // printf("IndexFile::create_index %d source_length=%jd source=%p progress=%p\n",
513 // __LINE__,
514 // source_length,
515 // source,
516 // progress);
517 SET_TRACE
518                 while(position < source_length && !result)
519                 {
520 SET_TRACE
521                         if(source_length - position < fragment_size && fragment_size == buffersize) fragment_size = source_length - position;
522
523                         index_thread->input_lock[current_buffer]->lock("IndexFile::create_index 1");
524                         index_thread->input_len[current_buffer] = fragment_size;
525
526 SET_TRACE
527                         int cancelled = progress->update(position);
528 //printf("IndexFile::create_index cancelled=%d\n", cancelled);
529 SET_TRACE
530                         if(cancelled ||
531                                 index_thread->interrupt_flag ||
532                                 interrupt_flag)
533                         {
534                                 result = 3;
535                         }
536
537
538 SET_TRACE
539                         if(source && !result)
540                         {
541 SET_TRACE
542                                 for(int channel = 0;
543                                         !result && channel < source_channels;
544                                         channel++)
545                                 {
546 // Read from source file
547                                         source->set_audio_position(position);
548                                         source->set_channel(channel);
549
550                                         if(source->read_samples(
551                                                 index_thread->buffer_in[current_buffer][channel],
552                                                 fragment_size))
553                                                 result = 1;
554                                 }
555 SET_TRACE
556                         }
557                         else
558                         if(render_engine && !result)
559                         {
560 SET_TRACE
561                                 if(render_engine->arender)
562                                 {
563                                         result = render_engine->arender->process_buffer(
564                                                 index_thread->buffer_in[current_buffer],
565                                                 fragment_size,
566                                                 position);
567                                 }
568                                 else
569                                 {
570                                         for(int i = 0; i < source_channels; i++)
571                                         {
572                                                 bzero(index_thread->buffer_in[current_buffer][i]->get_data(),
573                                                         fragment_size * sizeof(double));
574                                         }
575                                 }
576 SET_TRACE
577                         }
578 SET_TRACE
579
580 // Release buffer to thread
581                         if(!result)
582                         {
583                                 index_thread->output_lock[current_buffer]->unlock();
584                                 current_buffer++;
585                                 if(current_buffer >= TOTAL_INDEX_BUFFERS) current_buffer = 0;
586                                 position += fragment_size;
587                         }
588                         else
589                         {
590                                 index_thread->input_lock[current_buffer]->unlock();
591                         }
592 SET_TRACE
593                 }
594
595
596 // end thread cleanly
597                 index_thread->input_lock[current_buffer]->lock("IndexFile::create_index 2");
598                 index_thread->last_buffer[current_buffer] = 1;
599                 index_thread->output_lock[current_buffer]->unlock();
600                 index_thread->stop_build();
601
602
603                 delete index_thread;
604
605         }
606
607
608
609         close_source();
610
611
612
613         open_index();
614
615         close_index();
616
617         mwindow->edl->set_index_file(indexable);
618         return 0;
619 }
620
621
622
623 int IndexFile::redraw_edits(int force)
624 {
625         int64_t difference = redraw_timer->get_scaled_difference(1000);
626
627         if(difference > 250 || force)
628         {
629                 redraw_timer->update();
630                 mwindow->gui->lock_window("IndexFile::redraw_edits");
631                 mwindow->edl->set_index_file(indexable);
632                 mwindow->gui->draw_indexes(indexable);
633                 mwindow->gui->unlock_window();
634         }
635         return 0;
636 }
637
638
639
640
641 int IndexFile::draw_index(
642         TrackCanvas *canvas,
643         ResourcePixmap *pixmap,
644         Edit *edit,
645         int x,
646         int w)
647 {
648         const int debug = 0;
649         IndexState *index_state = get_state();
650         int pane_number = canvas->pane->number;
651 //index_state->dump();
652
653 SET_TRACE
654         if(debug) printf("IndexFile::draw_index %d\n", __LINE__);
655         if(index_state->index_zoom == 0)
656         {
657                 printf(_("IndexFile::draw_index: index has 0 zoom\n"));
658                 return 0;
659         }
660         if(debug) printf("IndexFile::draw_index %d\n", __LINE__);
661
662 // test channel number
663         if(edit->channel > source_channels) return 1;
664         if(debug) printf("IndexFile::draw_index %d source_samplerate=%d "
665                         "w=%d samplerate=%jd zoom_sample=%jd\n",
666                 __LINE__, source_samplerate, w,
667                 mwindow->edl->session->sample_rate,
668                 mwindow->edl->local_session->zoom_sample);
669
670 // calculate a virtual x where the edit_x should be in floating point
671         double virtual_edit_x = 1.0 *
672                 edit->track->from_units(edit->startproject) *
673                 mwindow->edl->session->sample_rate /
674                 mwindow->edl->local_session->zoom_sample -
675                 mwindow->edl->local_session->view_start[pane_number];
676
677 // samples in segment to draw relative to asset
678         FloatAutos *speed_autos = !edit->track->has_speed() ? 0 :
679                 (FloatAutos *)edit->track->automation->autos[AUTOMATION_SPEED];
680         double project_zoom = mwindow->edl->local_session->zoom_sample;
681         int64_t edit_position = (x + pixmap->pixmap_x - virtual_edit_x) * project_zoom;
682         int64_t start_position = edit->startsource;
683         start_position += !speed_autos ? edit_position :
684                 speed_autos->automation_integral(edit->startproject, edit_position, PLAY_FORWARD);
685         int64_t end_position = edit->startsource;
686         edit_position = (x + w + pixmap->pixmap_x - virtual_edit_x) * project_zoom;
687         end_position += !speed_autos ? edit_position :
688                 speed_autos->automation_integral(edit->startproject, edit_position, PLAY_FORWARD);
689         double session_sample_rate = mwindow->edl->session->sample_rate;
690         double asset_over_session = (double)indexable->get_sample_rate() / session_sample_rate;
691         int64_t start_source = start_position * asset_over_session;
692         if( start_source < 0 ) start_source = 0;
693         int64_t start_index = start_source / index_state->index_zoom;
694         int64_t end_source = end_position * asset_over_session;
695         if( end_source < 0 ) end_source = 0;
696         int64_t end_index = end_source / index_state->index_zoom;
697 // start/length of index to read in floats
698         start_index *= 2;  end_index *= 2;
699 // length of index available in floats
700         int64_t size_index = index_state->index_status == INDEX_BUILDING ?
701                 index_state->get_channel_used(edit->channel) * 2 :
702                 index_state->get_index_size(edit->channel);
703 // Clamp length of index to read by available data
704         if( end_index >= size_index ) end_index = size_index;
705         int64_t length_index = end_index - start_index;
706         if( length_index <= 0 ) return 0;
707
708 // Start and length of fragment to read from file in bytes.
709         float *buffer = 0;
710         int buffer_shared = 0;
711         int rect_audio = mwindow->preferences->rectify_audio;
712         int data_h = edit->track->data_h;
713         int center_pixel = !rect_audio ? data_h/2 : data_h;
714         if( edit->track->show_titles() )
715                 center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
716
717         if( index_state->index_status == INDEX_BUILDING ) {
718 // index is in RAM, being built
719                 buffer = index_state->get_channel_buffer(edit->channel);
720                 if( !buffer ) return 0;
721                 buffer += start_index;
722                 buffer_shared = 1;
723         }
724         else {
725                 buffer = new float[length_index + 1];
726                 int64_t length_buffer = length_index * sizeof(float);
727 // add file/channel offset
728                 int64_t index_offset = index_state->get_index_offset(edit->channel);
729                 int64_t file_offset = (index_offset + start_index) * sizeof(float);
730                 int64_t file_pos = index_state->index_start + file_offset;
731                 int64_t read_length = file_length - file_pos;
732                 if( read_length > length_buffer )
733                         read_length = length_buffer;
734                 int64_t length_read = 0;
735                 if( read_length > 0 ) {
736                         fseek(fd, file_pos, SEEK_SET);
737                         length_read = fread(buffer, 1, read_length + sizeof(float), fd);
738                         length_read &= ~(sizeof(float)-1);
739                 }
740                 if( (read_length-=length_read) > 0 )
741                         memset((char*)buffer + length_read, 0, read_length);
742                 buffer_shared = 0;
743         }
744
745         canvas->set_color(mwindow->theme->audio_color);
746
747         int prev_y1 = center_pixel;
748         int prev_y2 = center_pixel;
749         int first_frame = 1;
750         int zoom_y = mwindow->edl->local_session->zoom_y * data_h /
751                         mwindow->edl->local_session->zoom_atrack;
752         if( !rect_audio ) zoom_y /= 2;
753         int max_y = center_pixel + zoom_y - 1;
754         edit_position = (x + pixmap->pixmap_x - virtual_edit_x) * project_zoom;
755         int64_t speed_position = edit->startsource;
756         speed_position += !speed_autos ? edit_position :
757                 speed_autos->automation_integral(edit->startproject, edit_position, PLAY_FORWARD);
758         int64_t source_position  = speed_position * asset_over_session;
759         int64_t index_position = source_position / index_state->index_zoom;
760         int64_t i = 2 * index_position - start_index;
761         CLAMP(i, 0, length_index);
762 SET_TRACE
763
764         for( int64_t x1=0; x1<w && i < length_index; ++x1 ) {
765                 float highsample = !rect_audio ? buffer[i] : fabsf(buffer[i]);  ++i;
766                 float lowsample  = !rect_audio ? buffer[i] : fabsf(buffer[i]);  ++i;
767                 int x2 = x1 + x + 1;
768                 edit_position = (x2 + pixmap->pixmap_x - virtual_edit_x) * project_zoom;
769                 int64_t speed_position = edit->startsource;
770                 speed_position += !speed_autos ? edit_position :
771                         speed_autos->automation_integral(edit->startproject, edit_position, PLAY_FORWARD);
772                 source_position  = speed_position * asset_over_session;
773                 index_position = source_position / index_state->index_zoom;
774                 int64_t k = 2 * index_position - start_index;
775                 CLAMP(k, 0, length_index);
776                 while( i < k ) {
777                         float high = !rect_audio ? buffer[i] : fabsf(buffer[i]);
778                         highsample = MAX(highsample, high); ++i;
779                         float low  = !rect_audio ? buffer[i] : fabsf(buffer[i]);
780                         lowsample = MIN(lowsample, low);   ++i;
781                 }
782
783                 int y1 = (int)(center_pixel - highsample * zoom_y);
784                 int y2 = (int)(center_pixel - lowsample * zoom_y);
785                 CLAMP(y1, 0, max_y);  int next_y1 = y1;
786                 CLAMP(y2, 0, max_y);  int next_y2 = y2;
787 //printf("draw_line (%f,%f) = %d,%d,  %d,%d\n", lowsample, highsample, x2, y1, x2, y2);
788
789 //SET_TRACE
790 // A different algorithm has to be used if it's 1 sample per pixel and the
791 // index is used.  Now the min and max values are equal so we join the max samples.
792                 if(mwindow->edl->local_session->zoom_sample == 1) {
793                         canvas->draw_bline(x2 - 1, !rect_audio ? prev_y1 : center_pixel, x2, y1, pixmap);
794                 }
795                 else {
796 // Extend line height if it doesn't connect to previous line
797                         if(!first_frame) {
798                                 if(y1 > prev_y2) y1 = prev_y2 + 1;
799                                 if(y2 < prev_y1) y2 = prev_y1 - 1;
800                         }
801                         else {
802                                 first_frame = 0;
803                         }
804                         canvas->draw_bline(x2, y1, x2, !rect_audio ? y2 : center_pixel, pixmap);
805                 }
806                 prev_y1 = next_y1;
807                 prev_y2 = next_y2;
808         }
809
810 SET_TRACE
811
812         if(!buffer_shared) delete [] buffer;
813 SET_TRACE
814         if(debug) printf("IndexFile::draw_index %d\n", __LINE__);
815         return 0;
816 }
817
818 int IndexFile::close_index()
819 {
820         if(fd)
821         {
822                 fclose(fd);
823                 fd = 0;
824         }
825         return 0;
826 }
827
828 int IndexFile::remove_index()
829 {
830         IndexState *index_state = get_state();
831         if(index_state->index_status == INDEX_READY ||
832                 index_state->index_status == INDEX_NOTTESTED)
833         {
834                 close_index();
835                 remove(index_filename);
836         }
837         return 0;
838 }
839
840 int IndexFile::read_info(Indexable *test_indexable)
841 {
842         const int debug = 0;
843
844 // Store format in actual asset.
845 // If it's a nested EDL, we never want the format, just the index info.
846         if(!test_indexable) test_indexable = indexable;
847         if(!test_indexable) return 1;
848
849         IndexState * index_state = test_indexable->index_state;
850         if(index_state->index_status == INDEX_NOTTESTED)
851         {
852 // read start of index data
853                 int temp = fread((char*)&(index_state->index_start), sizeof(int64_t), 1, fd);
854 //printf("IndexFile::read_info %d %f\n", __LINE__, test_indexable->get_frame_rate());
855
856                 if(!temp) return 1;
857 // read test_indexable info from index
858                 char *data;
859
860                 data = new char[index_state->index_start];
861                 temp = fread(data, index_state->index_start - sizeof(int64_t), 1, fd);
862                 if(!temp) return 1;
863
864                 data[index_state->index_start - sizeof(int64_t)] = 0;
865                 FileXML xml;
866                 xml.read_from_string(data);
867                 delete [] data;
868
869
870
871 // Read the file format & index state.
872                 if(test_indexable->is_asset)
873                 {
874                         Asset *test_asset = (Asset *)test_indexable;
875                         Asset *asset = new Asset;
876                         asset->read(&xml);
877                         int ret = 0;
878 //printf("IndexFile::read_info %d %f\n", __LINE__, asset->get_frame_rate());
879
880                         if( asset->format == FILE_UNKNOWN ||
881                             test_asset->format != asset->format ) {
882 if(debug) printf("IndexFile::read_info %d\n", __LINE__);
883                                 ret = 1;
884                         }
885                         asset->remove_user();
886                         if( ret ) return ret;
887                 }
888                 else
889                 {
890 // Read only the index state for a nested EDL
891                         int result = 0;
892 if(debug) printf("IndexFile::read_info %d\n", __LINE__);
893                         while(!result)
894                         {
895                                 result = xml.read_tag();
896                                 if(!result)
897                                 {
898                                         if(xml.tag.title_is("INDEX"))
899                                         {
900                                                 index_state->read_xml(&xml, source_channels);
901 if(debug) printf("IndexFile::read_info %d\n", __LINE__);
902 if(debug) index_state->dump();
903                                                 result = 1;
904                                         }
905                                 }
906                         }
907                 }
908         }
909
910         return 0;
911 }
912
913
914
915
916
917
918
919