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