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