r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / indexfile.C
blobadcae46e3944e6f9924650440a6e70fb16135597
1 #include "assets.h"
2 #include "clip.h"
3 #include "edit.h"
4 #include "edl.h"
5 #include "edlsession.h"
6 #include "filexml.h"
7 #include "filesystem.h"
8 #include "errorbox.h"
9 #include "file.h"
10 #include "indexfile.h"
11 #include "indexthread.h"
12 #include "localsession.h"
13 #include "mainprogress.h"
14 #include "mwindow.h"
15 #include "mwindowgui.h"
16 #include "preferences.h"
17 #include "resourcepixmap.h"
18 #include "theme.h"
19 #include "timer.h"
20 #include "trackcanvas.h"
21 #include "tracks.h"
22 #include "vframe.h"
24 #include <string.h>
25 #include <libintl.h>
26 #define _(String) gettext(String)
27 #define gettext_noop(String) String
28 #define N_(String) gettext_noop (String)
30 // Use native sampling rates for files so the same index can be used in
31 // multiple projects.
33 IndexFile::IndexFile(MWindow *mwindow)
35 //printf("IndexFile::IndexFile 1\n");
36         this->mwindow = mwindow;
37 //printf("IndexFile::IndexFile 2\n");
38         file = 0;
39         interrupt_flag = 0;
40         redraw_timer = new Timer;
43 IndexFile::IndexFile(MWindow *mwindow, Asset *asset)
45 //printf("IndexFile::IndexFile 2\n");
46         file = 0;
47         this->mwindow = mwindow;
48         this->asset = asset;
49         interrupt_flag = 0;
50         redraw_timer = new Timer;
53 IndexFile::~IndexFile()
55 //printf("IndexFile::~IndexFile 1\n");
56         delete redraw_timer;
59 int IndexFile::open_index(Asset *asset)
61 // use buffer if being built
62         this->asset = asset;
63         int result = 0;
65 //printf("IndexFile::open_index 1\n");
66         if(asset->index_status == INDEX_BUILDING)
67         {
68 // use buffer
69                 result = 0;
70         }
71         else
72         if(!(result = open_file()))
73         {
74 // opened existing file
75                 if(read_info())
76                 {
77 //printf("IndexFile::open_index 2\n");
78                         result = 1;
79                         close_index();
80                 }
81                 else
82                 {
83 //printf("IndexFile::open_index 3\n");
84                         asset->index_status = INDEX_READY;
85                 }
86         }
87         else
88         {
89                 result = 1;
90         }
91 //printf("IndexFile::open_index 4 %d\n", result);
93         return result;
96 int IndexFile::open_index(MWindow *mwindow, Asset *asset)
98         return open_index(asset);
101 void IndexFile::delete_index(Preferences *preferences, Asset *asset)
103         char index_filename[BCTEXTLEN];
104         char source_filename[BCTEXTLEN];
105         get_index_filename(source_filename, 
106                 preferences->index_directory,
107                 index_filename, 
108                 asset->path);
109 //printf("IndexFile::delete_index %s %s\n", source_filename, index_filename);
110         remove(index_filename);
113 int IndexFile::open_file()
115         int result = 0;
116         get_index_filename(source_filename, 
117                 mwindow->preferences->index_directory,
118                 index_filename, 
119                 asset->path);
121 //printf("IndexFile::open_file 1 %s\n", index_filename);
122         if(file = fopen(index_filename, "rb")) 
123         {
124 // Index file already exists.
125 // Get its last size without changing the status.
126                 Asset test_asset;
127                 test_asset = *asset;
128                 read_info(&test_asset);
130                 FileSystem fs;
131 //printf("IndexFile::open_file 1.5 %s %u %u\n", 
132 //index_filename, 
133 //fs.get_date(index_filename), 
134 //fs.get_date(test_asset.path));
135                 if(fs.get_date(index_filename) < fs.get_date(test_asset.path))
136                 {
137 // index older than source
138 //printf("IndexFile::open_file 2\n", index_filename);
139                         result = 2;
140                         fclose(file);
141                 }
142                 else
143                 if(fs.get_size(asset->path) != test_asset.index_bytes)
144                 {
145 // source file is a different size than index source file
146 //printf("IndexFile::open_file 3 %s %lld %lld %lld\n", 
147 //index_filename, 
148 //fs.get_size(asset->path), 
149 //test_asset.index_bytes,
150 //asset->index_bytes);
151                         result = 2;
152                         fclose(file);   
153                 }
154                 else
155                 {
156 //printf("IndexFile::open_file 4 %s %lld %lld %lld\n", 
157 //index_filename, 
158 //fs.get_size(asset->path), 
159 //test_asset.index_bytes,
160 //asset->index_bytes);
161                         fseek(file, 0, SEEK_END);
162                         file_length = ftell(file);
163                         fseek(file, 0, SEEK_SET);
164                         result = 0;
165                 }
166         }
167         else
168         {
169 // doesn't exist
170 //printf("IndexFile::open_file 5\n", index_filename);
171                 result = 1;
172         }
174         return result;
177 int IndexFile::open_source(File *source)
179 //printf("IndexFile::open_source %p %s\n", asset, asset->path);
180         if(source->open_file(mwindow->plugindb, 
181                 asset, 
182                 1, 
183                 0, 
184                 0, 
185                 0))
186         {
187                 //printf("IndexFile::open_source() Couldn't open %s.\n", asset->path);
188                 return 1;
189         }
190         else
191         {
192                 FileSystem fs;
193                 asset->index_bytes = fs.get_size(asset->path);
194                 return 0;
195         }
198 int64_t IndexFile::get_required_scale(File *source)
200         int64_t result = 1;
201 // total length of input file
202         int64_t length_source = source->get_audio_length(0);  
204 // get scale of index file
205 //      if(length_source > mwindow->preferences->index_size)
206 //      {
207 // Total peaks which may be stored in buffer
208                 int64_t peak_count = mwindow->preferences->index_size / (2 * sizeof(float) * asset->channels);
209                 for(result = 1; 
210                         length_source / result > peak_count; 
211                         result *= 2)
212                         ;
213 //      }
214 //      else
215 //      {
216 // too small to build an index for
217 //              result = 0;
218 //      }
220 // Takes too long to draw from source on a CDROM.  Make indexes for
221 // everything.
223         return result;
226 int IndexFile::get_index_filename(char *source_filename, 
227         char *index_directory, 
228         char *index_filename, 
229         char *input_filename)
231 // Replace slashes and dots
232         int i, j;
233         int len = strlen(input_filename);
234         for(i = 0, j = 0; i < len; i++)
235         {
236                 if(input_filename[i] != '/' &&
237                         input_filename[i] != '.')
238                         source_filename[j++] = input_filename[i];
239                 else
240                 {
241                         if(i > 0)
242                                 source_filename[j++] = '_';
243                 }
244         }
245         source_filename[j] = 0;
246         FileSystem fs;
247         fs.join_names(index_filename, index_directory, source_filename);
248         strcat(index_filename, ".idx");
249         return 0;
252 int IndexFile::interrupt_index()
254         interrupt_flag = 1;
255         return 0;
258 // Read data into buffers
260 int IndexFile::create_index(Asset *asset, MainProgressBar *progress)
262         int result = 0;
263         IndexThread *index_thread;
264         this->mwindow = mwindow;
265         this->asset = asset;
266         interrupt_flag = 0;
268 // open the source file
269         File source;
270         if(open_source(&source)) return 1;
272         asset->index_zoom = get_required_scale(&source);
273 //printf("IndexFile::create_index 1 %d %s\n", asset->index_zoom, asset->path);
275 // Indexes are now built for everything since it takes too long to draw
276 // from CDROM source.
278 // too small to build an index for.
279 //      if(asset->index_zoom == 0)
280 //      {
281 //              source.close_file();
282 //              asset->index_status = INDEX_TOOSMALL;
283 // // Update the EDL and timeline
284 //              redraw_edits(1);
285 // //printf("IndexFile::create_index 2\n");
286 //              return 1;
287 //      }
288 //printf("IndexFile::create_index 2\n");
290 // total length of input file
291         int64_t length_source = source.get_audio_length(0);  
293 // get amount to read at a time in floats
294         int64_t buffersize = 65536;
295         char string[1024];
296         get_index_filename(source_filename, 
297                 mwindow->preferences->index_directory, 
298                 index_filename, 
299                 asset->path);
300         sprintf(string, _("Creating %s."), index_filename);
302         progress->update_title(string);
303         progress->update_length(length_source);
304         redraw_timer->update();
306 // thread out index thread
307         index_thread = new IndexThread(mwindow, 
308                 this, 
309                 asset, 
310                 index_filename, 
311                 buffersize, 
312                 length_source);
313         index_thread->start_build();
315         int64_t position = 0;            // current sample in source file
316         int64_t fragment_size = buffersize;
317         int current_buffer = 0;
318 //printf("IndexFile::create_index 3\n");
320 // pass through file once
321         while(position < length_source && !result)
322         {
323                 if(length_source - position < fragment_size && fragment_size == buffersize) fragment_size = length_source - position;
325 //printf("IndexFile::create_index 1 %d\n", position);
326                 index_thread->input_lock[current_buffer].lock();
327                 index_thread->input_len[current_buffer] = fragment_size;
329 //printf("IndexFile::create_index 2 %d\n", position);
330                 int cancelled = progress->update(position);
331 //printf("IndexFile::create_index 3 %d\n", position);
332                 if(cancelled || 
333                         index_thread->interrupt_flag || 
334                         interrupt_flag)
335                 {
336                         result = 3;    // user cancelled
337                 }
339 //printf("IndexFile::create_index 4 %d\n", position);
340                 for(int channel = 0; !result && channel < asset->channels; channel++)
341                 {
342                         source.set_audio_position(position, 0);
343                         source.set_channel(channel);
345 // couldn't read
346 //printf("IndexFile::create_index 5\n");
347                         if(source.read_samples(index_thread->buffer_in[current_buffer][channel], 
348                                 fragment_size,
349                                 0)) result = 1;
350 //printf("IndexFile::create_index 6\n");
351                 }
352 //printf("IndexFile::create_index 7 %d\n", position);
354                 if(!result)
355                 {
356                         index_thread->output_lock[current_buffer].unlock();
357                         current_buffer++;
358                         if(current_buffer >= TOTAL_BUFFERS) current_buffer = 0;
359                         position += fragment_size;
360                 }
361                 else
362                 {
363                         index_thread->input_lock[current_buffer].unlock();
364                 }
365 //printf("IndexFile::create_index 8 %d\n", position);
366         }
367 //printf("IndexFile::create_index 10\n");
369 // end thread cleanly
370         index_thread->input_lock[current_buffer].lock();
371         index_thread->last_buffer[current_buffer] = 1;
372         index_thread->output_lock[current_buffer].unlock();
374         index_thread->stop_build();
376         source.close_file();
378         delete index_thread;
380         open_index(asset);
381         close_index();
382         mwindow->edl->set_index_file(asset);
383 //printf("IndexFile::create_index 11\n");
384         return 0;
388 int IndexFile::create_index(MWindow *mwindow, 
389                 Asset *asset, 
390                 MainProgressBar *progress)
392         return create_index(asset, progress);
397 int IndexFile::redraw_edits(int force)
399         int64_t difference = redraw_timer->get_scaled_difference(1000);
401 //printf("IndexFile::redraw_edits 1 %d %d\n", difference, force);
402         if(difference > 250 || force)
403         {
404                 redraw_timer->update();
405 // Can't lock window here since the window is only redrawn when the pixel
406 // count changes.
407 //printf("IndexFile::redraw_edits 2\n");
408                 mwindow->gui->lock_window();
409                 mwindow->edl->set_index_file(asset);
410 //printf("IndexFile::redraw_edits 3\n");
411                 mwindow->gui->canvas->draw_indexes(asset);
412 //printf("IndexFile::redraw_edits 4\n");
413                 asset->old_index_end = asset->index_end;
414                 mwindow->gui->unlock_window();
415 //printf("IndexFile::redraw_edits 5\n");
416         }
417         return 0;
423 int IndexFile::draw_index(ResourcePixmap *pixmap, Edit *edit, int x, int w)
425 // check against index_end when being built
426         if(asset->index_zoom == 0)
427         {
428                 printf(_("IndexFile::draw_index: index has 0 zoom\n"));
429                 return 0;
430         }
432 // samples in segment to draw relative to asset
433         double asset_over_session = (double)edit->asset->sample_rate / 
434                 mwindow->edl->session->sample_rate;
435         int64_t startsource = (int64_t)(((pixmap->pixmap_x - pixmap->edit_x + x) * 
436                 mwindow->edl->local_session->zoom_sample + 
437                 edit->startsource) * 
438                 asset_over_session);
439         int64_t length = (int64_t)(w * 
440                 mwindow->edl->local_session->zoom_sample * 
441                 asset_over_session);
443         if(asset->index_status == INDEX_BUILDING)
444         {
445                 if(startsource + length > asset->index_end)
446                         length = asset->index_end - startsource;
447         }
449 // length of index to read in samples * 2
450         int64_t lengthindex = length / asset->index_zoom * 2; 
451 // start of data in samples
452         int64_t startindex = startsource / asset->index_zoom * 2;  
453         int64_t length_read;   // Actual length read from file in bytes
454         int64_t startfile, lengthfile;    // Start and length of fragment to read from file in bytes.
455         float *buffer = 0;
456         int buffer_shared = 0;
457         int i;
458         int center_pixel = mwindow->edl->local_session->zoom_track / 2;
459         if(mwindow->edl->session->show_titles) center_pixel += mwindow->theme->title_bg_data->get_h();
460         int miny = center_pixel - mwindow->edl->local_session->zoom_track / 2;
461         int maxy = center_pixel + mwindow->edl->local_session->zoom_track / 2;
462         int x1 = 0, y1, y2;
463 // get zoom_sample relative to index zoomx
464         double index_frames_per_pixel = mwindow->edl->local_session->zoom_sample / 
465                 asset->index_zoom * 
466                 asset_over_session;
468 // test channel number
469         if(edit->channel > asset->channels) return 1;
471 // get channel offset
472         startindex += asset->get_index_offset(edit->channel);
475         if(asset->index_status == INDEX_BUILDING)
476         {
477 // index is in RAM, being built
478                 buffer = &(asset->index_buffer[startindex]);
479                 buffer_shared = 1;
480         }
481         else
482         {
483 // index is stored in a file
484                 buffer = new float[lengthindex + 1];
485                 buffer_shared = 0;
486                 startfile = asset->index_start + startindex * sizeof(float);
487                 lengthfile = lengthindex * sizeof(float);
488                 length_read = 0;
490                 if(startfile < file_length)
491                 {
492                         fseek(file, startfile, SEEK_SET);
494                         length_read = lengthfile;
495                         if(startfile + length_read > file_length)
496                                 length_read = file_length - startfile;
498                         fread(buffer, length_read + sizeof(float), 1, file);
499                 }
501                 if(length_read < lengthfile)
502                         for(i = length_read / sizeof(float); 
503                                 i < lengthfile / sizeof(float); 
504                                 i++)
505                                 buffer[i] = 0;
506         }
510         pixmap->canvas->set_color(mwindow->theme->audio_color);
513         double current_frame = 0;
514         float highsample = buffer[0];
515         float lowsample = buffer[1];
516         int prev_y1 = center_pixel;
517         int prev_y2 = center_pixel;
518         int first_frame = 1;
520         for(int bufferposition = 0; 
521                 bufferposition < lengthindex; 
522                 bufferposition += 2)
523         {
524                 if(current_frame >= index_frames_per_pixel)
525                 {
526                         int next_y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
527                         int next_y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
528                         int y1 = next_y1;
529                         int y2 = next_y2;
531 // A different algorithm has to be used if it's 1 sample per pixel and the
532 // index is used.  Now the min and max values are equal so we join the max samples.
533                         if(mwindow->edl->local_session->zoom_sample == 1)
534                         {
535                                 pixmap->canvas->draw_line(x1 + x - 1, prev_y1, x1 + x, y1, pixmap);
536                         }
537                         else
538                         {
539 // Extend line height if it doesn't connect to previous line
540                                 if(!first_frame)
541                                 {
542                                         if(y1 > prev_y2) y1 = prev_y2 + 1;
543                                         if(y2 < prev_y1) y2 = prev_y1 - 1;
544                                 }
545                                 else
546                                 {
547                                         first_frame = 0;
548                                 }
549                                 pixmap->canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
550                         }
551                         current_frame -= index_frames_per_pixel;
552                         x1++;
553                         prev_y1 = next_y1;
554                         prev_y2 = next_y2;
555                         highsample = buffer[bufferposition];
556                         lowsample = buffer[bufferposition + 1];
557                 }
559                 current_frame++;
560                 highsample = MAX(highsample, buffer[bufferposition]);
561                 lowsample = MIN(lowsample, buffer[bufferposition + 1]);
562         }
564 // Get last column
565         if(current_frame)
566         {
567                 y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
568                 y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
569                 pixmap->canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
570         }
575         if(!buffer_shared) delete [] buffer;
576         return 0;
579 int IndexFile::close_index()
581         if(file)
582         {
583                 fclose(file);
584                 file = 0;
585         }
588 int IndexFile::remove_index()
590         if(asset->index_status == INDEX_READY || asset->index_status == INDEX_NOTTESTED)
591         {
592                 close_index();
593                 remove(index_filename);
594         }
597 int IndexFile::read_info(Asset *test_asset)
599 //printf("IndexFile::read_info 1 %p\n", test_asset);
600         if(!test_asset) test_asset = asset;
601 //printf("IndexFile::read_info 2 %d\n", test_asset->index_status);
602         if(test_asset->index_status == INDEX_NOTTESTED)
603         {
604 // read start of index data
605                 fread((char*)&(test_asset->index_start), sizeof(int64_t), 1, file);
607 // read test_asset info from index
608                 char *data;
609                 
610                 data = new char[test_asset->index_start];
611                 fread(data, test_asset->index_start - sizeof(int64_t), 1, file);
612                 data[test_asset->index_start - sizeof(int64_t)] = 0;
613                 FileXML xml;
614                 xml.read_from_string(data);
615                 test_asset->read(mwindow->plugindb, &xml);
617                 delete [] data;
618                 if(test_asset->format == FILE_UNKNOWN)
619                 {
620 //printf("IndexFile::read_info 3\n");
621                         return 1;
622                 }
623         }
624         return 0;