r602: Fix baver's code... don't insert timecode when show_tc is not set
[cinelerra_cv/mob.git] / cinelerra / indexfile.C
blob01e24506468086d41554d229a1a89aaa430efffa
1 #include "asset.h"
2 #include "clip.h"
3 #include "condition.h"
4 #include "edit.h"
5 #include "edl.h"
6 #include "edlsession.h"
7 #include "filexml.h"
8 #include "filesystem.h"
9 #include "errorbox.h"
10 #include "file.h"
11 #include "indexfile.h"
12 #include "indexthread.h"
13 #include "language.h"
14 #include "localsession.h"
15 #include "mainprogress.h"
16 #include "mwindow.h"
17 #include "mwindowgui.h"
18 #include "preferences.h"
19 #include "resourcepixmap.h"
20 #include "theme.h"
21 #include "bctimer.h"
22 #include "trackcanvas.h"
23 #include "tracks.h"
24 #include "vframe.h"
26 // Use native sampling rates for files so the same index can be used in
27 // multiple projects.
29 IndexFile::IndexFile(MWindow *mwindow)
31 //printf("IndexFile::IndexFile 1\n");
32         this->mwindow = mwindow;
33 //printf("IndexFile::IndexFile 2\n");
34         file = 0;
35         interrupt_flag = 0;
36         redraw_timer = new Timer;
39 IndexFile::IndexFile(MWindow *mwindow, Asset *asset)
41 //printf("IndexFile::IndexFile 2\n");
42         file = 0;
43         this->mwindow = mwindow;
44         this->asset = asset;
45         interrupt_flag = 0;
46         redraw_timer = new Timer;
49 IndexFile::~IndexFile()
51 //printf("IndexFile::~IndexFile 1\n");
52         delete redraw_timer;
55 int IndexFile::open_index(Asset *asset)
57 // use buffer if being built
58         this->asset = asset;
59         int result = 0;
61 //printf("IndexFile::open_index 1\n");
62         if(asset->index_status == INDEX_BUILDING)
63         {
64 // use buffer
65                 result = 0;
66         }
67         else
68         if(!(result = open_file()))
69         {
70 // opened existing file
71                 if(read_info())
72                 {
73 //printf("IndexFile::open_index 2\n");
74                         result = 1;
75                         close_index();
76                 }
77                 else
78                 {
79 //printf("IndexFile::open_index 3\n");
80                         asset->index_status = INDEX_READY;
81                 }
82         }
83         else
84         {
85                 result = 1;
86         }
87 //printf("IndexFile::open_index 4 %d\n", result);
89         return result;
92 int IndexFile::open_index(MWindow *mwindow, Asset *asset)
94         return open_index(asset);
97 void IndexFile::delete_index(Preferences *preferences, Asset *asset)
99         char index_filename[BCTEXTLEN];
100         char source_filename[BCTEXTLEN];
101         get_index_filename(source_filename, 
102                 preferences->index_directory,
103                 index_filename, 
104                 asset->path);
105 //printf("IndexFile::delete_index %s %s\n", source_filename, index_filename);
106         remove(index_filename);
109 int IndexFile::open_file()
111         int result = 0;
112         get_index_filename(source_filename, 
113                 mwindow->preferences->index_directory,
114                 index_filename, 
115                 asset->path);
117 //printf("IndexFile::open_file 1 %s\n", index_filename);
118         if(file = fopen(index_filename, "rb")) 
119         {
120 // Index file already exists.
121 // Get its last size without changing the status.
122                 Asset test_asset;
123                 test_asset = *asset;
124                 read_info(&test_asset);
126                 FileSystem fs;
127 //printf("IndexFile::open_file 1.5 %s %u %u\n", 
128 //index_filename, 
129 //fs.get_date(index_filename), 
130 //fs.get_date(test_asset.path));
131                 if(fs.get_date(index_filename) < fs.get_date(test_asset.path))
132                 {
133 // index older than source
134 //printf("IndexFile::open_file 2\n", index_filename);
135                         result = 2;
136                         fclose(file);
137                 }
138                 else
139                 if(fs.get_size(asset->path) != test_asset.index_bytes)
140                 {
141 // source file is a different size than index source file
142 //printf("IndexFile::open_file 3 %s %lld %lld %lld\n", 
143 //index_filename, 
144 //fs.get_size(asset->path), 
145 //test_asset.index_bytes,
146 //asset->index_bytes);
147                         result = 2;
148                         fclose(file);   
149                 }
150                 else
151                 {
152 //printf("IndexFile::open_file 4 %s %lld %lld %lld\n", 
153 //index_filename, 
154 //fs.get_size(asset->path), 
155 //test_asset.index_bytes,
156 //asset->index_bytes);
157                         fseek(file, 0, SEEK_END);
158                         file_length = ftell(file);
159                         fseek(file, 0, SEEK_SET);
160                         result = 0;
161                 }
162         }
163         else
164         {
165 // doesn't exist
166 //printf("IndexFile::open_file 5\n", index_filename);
167                 result = 1;
168         }
170         return result;
173 int IndexFile::open_source(File *source)
175 //printf("IndexFile::open_source %p %s\n", asset, asset->path);
176         if(source->open_file(mwindow->plugindb, 
177                 asset, 
178                 1, 
179                 0, 
180                 0, 
181                 0))
182         {
183                 //printf("IndexFile::open_source() Couldn't open %s.\n", asset->path);
184                 return 1;
185         }
186         else
187         {
188                 FileSystem fs;
189                 asset->index_bytes = fs.get_size(asset->path);
190                 return 0;
191         }
194 int64_t IndexFile::get_required_scale(File *source)
196         int64_t result = 1;
197 // total length of input file
198         int64_t length_source = source->get_audio_length(0);  
200 // get scale of index file
201 //      if(length_source > mwindow->preferences->index_size)
202 //      {
203 // Total peaks which may be stored in buffer
204                 int64_t peak_count = mwindow->preferences->index_size / (2 * sizeof(float) * asset->channels);
205                 for(result = 1; 
206                         length_source / result > peak_count; 
207                         result *= 2)
208                         ;
209 //      }
210 //      else
211 //      {
212 // too small to build an index for
213 //              result = 0;
214 //      }
216 // Takes too long to draw from source on a CDROM.  Make indexes for
217 // everything.
219         return result;
222 int IndexFile::get_index_filename(char *source_filename, 
223         char *index_directory, 
224         char *index_filename, 
225         char *input_filename)
227 // Replace slashes and dots
228         int i, j;
229         int len = strlen(input_filename);
230         for(i = 0, j = 0; i < len; i++)
231         {
232                 if(input_filename[i] != '/' &&
233                         input_filename[i] != '.')
234                         source_filename[j++] = input_filename[i];
235                 else
236                 {
237                         if(i > 0)
238                                 source_filename[j++] = '_';
239                 }
240         }
241         source_filename[j] = 0;
242         FileSystem fs;
243         fs.join_names(index_filename, index_directory, source_filename);
244         strcat(index_filename, ".idx");
245         return 0;
248 int IndexFile::interrupt_index()
250         interrupt_flag = 1;
251         return 0;
254 // Read data into buffers
256 int IndexFile::create_index(Asset *asset, MainProgressBar *progress)
258         int result = 0;
259         IndexThread *index_thread;
260         this->mwindow = mwindow;
261         this->asset = asset;
262         interrupt_flag = 0;
264 // open the source file
265         File source;
266         if(open_source(&source)) return 1;
268         asset->index_zoom = get_required_scale(&source);
270 // Indexes are now built for everything since it takes too long to draw
271 // from CDROM source.
274 // total length of input file
275         int64_t length_source = source.get_audio_length(0);  
277 // get amount to read at a time in floats
278         int64_t buffersize = 65536;
279         char string[1024];
280         get_index_filename(source_filename, 
281                 mwindow->preferences->index_directory, 
282                 index_filename, 
283                 asset->path);
284         sprintf(string, _("Creating %s."), index_filename);
286         progress->update_title(string);
287         progress->update_length(length_source);
288         redraw_timer->update();
290 // thread out index thread
291         index_thread = new IndexThread(mwindow, 
292                 this, 
293                 asset, 
294                 index_filename, 
295                 buffersize, 
296                 length_source);
297         index_thread->start_build();
299 // current sample in source file
300         int64_t position = 0;
301         int64_t fragment_size = buffersize;
302         int current_buffer = 0;
305 // pass through file once
306         while(position < length_source && !result)
307         {
308                 if(length_source - position < fragment_size && fragment_size == buffersize) fragment_size = length_source - position;
310                 index_thread->input_lock[current_buffer]->lock("IndexFile::create_index 1");
311                 index_thread->input_len[current_buffer] = fragment_size;
313                 int cancelled = progress->update(position);
314                 if(cancelled || 
315                         index_thread->interrupt_flag || 
316                         interrupt_flag)
317                 {
318                         result = 3;
319                 }
321                 for(int channel = 0; !result && channel < asset->channels; channel++)
322                 {
323                         source.set_audio_position(position, 0);
324                         source.set_channel(channel);
326 // Read from source file
327                         if(source.read_samples(index_thread->buffer_in[current_buffer][channel], 
328                                 fragment_size,
329                                 0)) result = 1;
330                 }
332 // Release buffer to thread
333                 if(!result)
334                 {
335                         index_thread->output_lock[current_buffer]->unlock();
336                         current_buffer++;
337                         if(current_buffer >= TOTAL_BUFFERS) current_buffer = 0;
338                         position += fragment_size;
339                 }
340                 else
341                 {
342                         index_thread->input_lock[current_buffer]->unlock();
343                 }
344         }
346 // end thread cleanly
347         index_thread->input_lock[current_buffer]->lock("IndexFile::create_index 2");
348         index_thread->last_buffer[current_buffer] = 1;
349         index_thread->output_lock[current_buffer]->unlock();
351         index_thread->stop_build();
353         source.close_file();
355         delete index_thread;
357         open_index(asset);
358         close_index();
359         mwindow->edl->set_index_file(asset);
360 //printf("IndexFile::create_index 11\n");
361         return 0;
365 int IndexFile::create_index(MWindow *mwindow, 
366                 Asset *asset, 
367                 MainProgressBar *progress)
369         return create_index(asset, progress);
374 int IndexFile::redraw_edits(int force)
376         int64_t difference = redraw_timer->get_scaled_difference(1000);
378 //printf("IndexFile::redraw_edits 1 %d %d\n", difference, force);
379         if(difference > 250 || force)
380         {
381                 redraw_timer->update();
382 // Can't lock window here since the window is only redrawn when the pixel
383 // count changes.
384 //printf("IndexFile::redraw_edits 2\n");
385                 mwindow->gui->lock_window();
386                 mwindow->edl->set_index_file(asset);
387 //printf("IndexFile::redraw_edits 3\n");
388                 mwindow->gui->canvas->draw_indexes(asset);
389 //printf("IndexFile::redraw_edits 4\n");
390                 asset->old_index_end = asset->index_end;
391                 mwindow->gui->unlock_window();
392 //printf("IndexFile::redraw_edits 5\n");
393         }
394         return 0;
400 int IndexFile::draw_index(ResourcePixmap *pixmap, Edit *edit, int x, int w)
402 // check against index_end when being built
403         if(asset->index_zoom == 0)
404         {
405                 printf(_("IndexFile::draw_index: index has 0 zoom\n"));
406                 return 0;
407         }
408 // calculate a virtual x where the edit_x should be in floating point
409         double virtual_edit_x = 1.0 * edit->track->from_units(edit->startproject) * 
410                         mwindow->edl->session->sample_rate /
411                         mwindow->edl->local_session->zoom_sample - 
412                         mwindow->edl->local_session->view_start;
414 // samples in segment to draw relative to asset
415         double asset_over_session = (double)edit->asset->sample_rate / 
416                 mwindow->edl->session->sample_rate;
417         int64_t startsource = (int64_t)(((pixmap->pixmap_x - virtual_edit_x + x) * 
418                 mwindow->edl->local_session->zoom_sample + 
419                 edit->startsource) * 
420                 asset_over_session);
421 // just in case we get a numerical error 
422         if (startsource < 0) startsource = 0;
423         int64_t length = (int64_t)(w * 
424                 mwindow->edl->local_session->zoom_sample * 
425                 asset_over_session);
427         if(asset->index_status == INDEX_BUILDING)
428         {
429                 if(startsource + length > asset->index_end)
430                         length = asset->index_end - startsource;
431         }
433 // length of index to read in samples * 2
434         int64_t lengthindex = length / asset->index_zoom * 2; 
435 // start of data in samples
436         int64_t startindex = startsource / asset->index_zoom * 2;  
437         int64_t length_read;   // Actual length read from file in bytes
438         int64_t startfile, lengthfile;    // Start and length of fragment to read from file in bytes.
439         float *buffer = 0;
440         int buffer_shared = 0;
441         int i;
442         int center_pixel = mwindow->edl->local_session->zoom_track / 2;
443         if(mwindow->edl->session->show_titles) center_pixel += mwindow->theme->title_bg_data->get_h();
444         int miny = center_pixel - mwindow->edl->local_session->zoom_track / 2;
445         int maxy = center_pixel + mwindow->edl->local_session->zoom_track / 2;
446         int x1 = 0, y1, y2;
447 // get zoom_sample relative to index zoomx
448         double index_frames_per_pixel = mwindow->edl->local_session->zoom_sample / 
449                 asset->index_zoom * 
450                 asset_over_session;
452 // test channel number
453         if(edit->channel > asset->channels) return 1;
455 // get channel offset
456         startindex += asset->get_index_offset(edit->channel);
459         if(asset->index_status == INDEX_BUILDING)
460         {
461 // index is in RAM, being built
462                 buffer = &(asset->index_buffer[startindex]);
463                 buffer_shared = 1;
464         }
465         else
466         {
467 // index is stored in a file
468                 buffer = new float[lengthindex + 1];
469                 buffer_shared = 0;
470                 startfile = asset->index_start + startindex * sizeof(float);
471                 lengthfile = lengthindex * sizeof(float);
472                 length_read = 0;
474                 if(startfile < file_length)
475                 {
476                         fseek(file, startfile, SEEK_SET);
478                         length_read = lengthfile;
479                         if(startfile + length_read > file_length)
480                                 length_read = file_length - startfile;
482                         fread(buffer, length_read + sizeof(float), 1, file);
483                 }
485                 if(length_read < lengthfile)
486                         for(i = length_read / sizeof(float); 
487                                 i < lengthfile / sizeof(float); 
488                                 i++)
489                                 buffer[i] = 0;
490         }
494         pixmap->canvas->set_color(mwindow->theme->audio_color);
497         double current_frame = 0;
498         float highsample = buffer[0];
499         float lowsample = buffer[1];
500         int prev_y1 = center_pixel;
501         int prev_y2 = center_pixel;
502         int first_frame = 1;
504         for(int bufferposition = 0; 
505                 bufferposition < lengthindex; 
506                 bufferposition += 2)
507         {
508                 if(current_frame >= index_frames_per_pixel)
509                 {
510                         int next_y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
511                         int next_y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
512                         int y1 = next_y1;
513                         int y2 = next_y2;
515 // A different algorithm has to be used if it's 1 sample per pixel and the
516 // index is used.  Now the min and max values are equal so we join the max samples.
517                         if(mwindow->edl->local_session->zoom_sample == 1)
518                         {
519                                 pixmap->canvas->draw_line(x1 + x - 1, prev_y1, x1 + x, y1, pixmap);
520                         }
521                         else
522                         {
523 // Extend line height if it doesn't connect to previous line
524                                 if(!first_frame)
525                                 {
526                                         if(y1 > prev_y2) y1 = prev_y2 + 1;
527                                         if(y2 < prev_y1) y2 = prev_y1 - 1;
528                                 }
529                                 else
530                                 {
531                                         first_frame = 0;
532                                 }
533                                 pixmap->canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
534                         }
535                         current_frame -= index_frames_per_pixel;
536                         x1++;
537                         prev_y1 = next_y1;
538                         prev_y2 = next_y2;
539                         highsample = buffer[bufferposition];
540                         lowsample = buffer[bufferposition + 1];
541                 }
543                 current_frame++;
544                 highsample = MAX(highsample, buffer[bufferposition]);
545                 lowsample = MIN(lowsample, buffer[bufferposition + 1]);
546         }
548 // Get last column
549         if(current_frame)
550         {
551                 y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
552                 y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
553                 pixmap->canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
554         }
559         if(!buffer_shared) delete [] buffer;
560         return 0;
563 int IndexFile::close_index()
565         if(file)
566         {
567                 fclose(file);
568                 file = 0;
569         }
572 int IndexFile::remove_index()
574         if(asset->index_status == INDEX_READY || asset->index_status == INDEX_NOTTESTED)
575         {
576                 close_index();
577                 remove(index_filename);
578         }
581 int IndexFile::read_info(Asset *test_asset)
583 //printf("IndexFile::read_info 1 %p\n", test_asset);
584         if(!test_asset) test_asset = asset;
585 //printf("IndexFile::read_info 2 %d\n", test_asset->index_status);
586         if(test_asset->index_status == INDEX_NOTTESTED)
587         {
588 // read start of index data
589                 fread((char*)&(test_asset->index_start), sizeof(int64_t), 1, file);
591 // read test_asset info from index
592                 char *data;
593                 
594                 data = new char[test_asset->index_start];
595                 fread(data, test_asset->index_start - sizeof(int64_t), 1, file);
596                 data[test_asset->index_start - sizeof(int64_t)] = 0;
597                 FileXML xml;
598                 xml.read_from_string(data);
599                 test_asset->read(mwindow->plugindb, &xml);
601                 delete [] data;
602                 if(test_asset->format == FILE_UNKNOWN)
603                 {
604 //printf("IndexFile::read_info 3\n");
605                         return 1;
606                 }
607         }
608         return 0;