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