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