Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

indexfile.C

Go to the documentation of this file.
00001 #include "asset.h"
00002 #include "clip.h"
00003 #include "condition.h"
00004 #include "edit.h"
00005 #include "edl.h"
00006 #include "edlsession.h"
00007 #include "filexml.h"
00008 #include "filesystem.h"
00009 #include "errorbox.h"
00010 #include "file.h"
00011 #include "indexfile.h"
00012 #include "indexthread.h"
00013 #include "language.h"
00014 #include "localsession.h"
00015 #include "mainprogress.h"
00016 #include "mwindow.h"
00017 #include "mwindowgui.h"
00018 #include "preferences.h"
00019 #include "resourcepixmap.h"
00020 #include "theme.h"
00021 #include "bctimer.h"
00022 #include "trackcanvas.h"
00023 #include "tracks.h"
00024 #include "vframe.h"
00025 
00026 // Use native sampling rates for files so the same index can be used in
00027 // multiple projects.
00028 
00029 IndexFile::IndexFile(MWindow *mwindow)
00030 {
00031 //printf("IndexFile::IndexFile 1\n");
00032         this->mwindow = mwindow;
00033 //printf("IndexFile::IndexFile 2\n");
00034         file = 0;
00035         interrupt_flag = 0;
00036         redraw_timer = new Timer;
00037 }
00038 
00039 IndexFile::IndexFile(MWindow *mwindow, Asset *asset)
00040 {
00041 //printf("IndexFile::IndexFile 2\n");
00042         file = 0;
00043         this->mwindow = mwindow;
00044         this->asset = asset;
00045         interrupt_flag = 0;
00046         redraw_timer = new Timer;
00047 }
00048 
00049 IndexFile::~IndexFile()
00050 {
00051 //printf("IndexFile::~IndexFile 1\n");
00052         delete redraw_timer;
00053 }
00054 
00055 int IndexFile::open_index(Asset *asset)
00056 {
00057 // use buffer if being built
00058         this->asset = asset;
00059         int result = 0;
00060 
00061         if(asset->index_status == INDEX_BUILDING)
00062         {
00063 // use buffer
00064                 result = 0;
00065         }
00066         else
00067         if(!(result = open_file()))
00068         {
00069 // opened existing file
00070                 if(read_info())
00071                 {
00072                         result = 1;
00073                         close_index();
00074                 }
00075                 else
00076                 {
00077                         asset->index_status = INDEX_READY;
00078                 }
00079         }
00080         else
00081         {
00082                 result = 1;
00083         }
00084 
00085         return result;
00086 }
00087 
00088 int IndexFile::open_index(MWindow *mwindow, Asset *asset)
00089 {
00090         return open_index(asset);
00091 }
00092 
00093 void IndexFile::delete_index(Preferences *preferences, Asset *asset)
00094 {
00095         char index_filename[BCTEXTLEN];
00096         char source_filename[BCTEXTLEN];
00097         get_index_filename(source_filename, 
00098                 preferences->index_directory,
00099                 index_filename, 
00100                 asset->path);
00101 //printf("IndexFile::delete_index %s %s\n", source_filename, index_filename);
00102         remove(index_filename);
00103 }
00104 
00105 int IndexFile::open_file()
00106 {
00107         int result = 0;
00108         get_index_filename(source_filename, 
00109                 mwindow->preferences->index_directory,
00110                 index_filename, 
00111                 asset->path);
00112 
00113         if(file = fopen(index_filename, "rb"))
00114         {
00115 // Index file already exists.
00116 // Get its last size without changing the status.
00117                 Asset test_asset;
00118                 test_asset = *asset;
00119                 read_info(&test_asset);
00120 
00121                 FileSystem fs;
00122                 if(fs.get_date(index_filename) < fs.get_date(test_asset.path))
00123                 {
00124 // index older than source
00125                         result = 2;
00126                         fclose(file);
00127                 }
00128                 else
00129                 if(fs.get_size(asset->path) != test_asset.index_bytes)
00130                 {
00131 // source file is a different size than index source file
00132                         result = 2;
00133                         fclose(file);   
00134                 }
00135                 else
00136                 {
00137                         fseek(file, 0, SEEK_END);
00138                         file_length = ftell(file);
00139                         fseek(file, 0, SEEK_SET);
00140                         result = 0;
00141                 }
00142         }
00143         else
00144         {
00145 // doesn't exist
00146                 result = 1;
00147         }
00148 
00149         return result;
00150 }
00151 
00152 int IndexFile::open_source(File *source)
00153 {
00154 //printf("IndexFile::open_source %p %s\n", asset, asset->path);
00155         if(source->open_file(mwindow->preferences, 
00156                 asset, 
00157                 1, 
00158                 0, 
00159                 0, 
00160                 0))
00161         {
00162                 //printf("IndexFile::open_source() Couldn't open %s.\n", asset->path);
00163                 return 1;
00164         }
00165         else
00166         {
00167                 FileSystem fs;
00168                 asset->index_bytes = fs.get_size(asset->path);
00169                 return 0;
00170         }
00171 }
00172 
00173 int64_t IndexFile::get_required_scale(File *source)
00174 {
00175         int64_t result = 1;
00176 // total length of input file
00177         int64_t length_source = source->get_audio_length(0);  
00178 
00179 // get scale of index file
00180 //      if(length_source > mwindow->preferences->index_size)
00181 //      {
00182 // Total peaks which may be stored in buffer
00183                 int64_t peak_count = mwindow->preferences->index_size / (2 * sizeof(float) * asset->channels);
00184                 for(result = 1; 
00185                         length_source / result > peak_count; 
00186                         result *= 2)
00187                         ;
00188 //      }
00189 //      else
00190 //      {
00191 // too small to build an index for
00192 //              result = 0;
00193 //      }
00194 
00195 // Takes too long to draw from source on a CDROM.  Make indexes for
00196 // everything.
00197 
00198         return result;
00199 }
00200 
00201 int IndexFile::get_index_filename(char *source_filename, 
00202         char *index_directory, 
00203         char *index_filename, 
00204         char *input_filename)
00205 {
00206 // Replace slashes and dots
00207         int i, j;
00208         int len = strlen(input_filename);
00209         for(i = 0, j = 0; i < len; i++)
00210         {
00211                 if(input_filename[i] != '/' &&
00212                         input_filename[i] != '.')
00213                         source_filename[j++] = input_filename[i];
00214                 else
00215                 {
00216                         if(i > 0)
00217                                 source_filename[j++] = '_';
00218                 }
00219         }
00220         source_filename[j] = 0;
00221         FileSystem fs;
00222         fs.join_names(index_filename, index_directory, source_filename);
00223         strcat(index_filename, ".idx");
00224         return 0;
00225 }
00226 
00227 int IndexFile::interrupt_index()
00228 {
00229         interrupt_flag = 1;
00230         return 0;
00231 }
00232 
00233 // Read data into buffers
00234 
00235 int IndexFile::create_index(Asset *asset, MainProgressBar *progress)
00236 {
00237         int result = 0;
00238         this->mwindow = mwindow;
00239         this->asset = asset;
00240         interrupt_flag = 0;
00241 
00242 // open the source file
00243         File source;
00244         if(open_source(&source)) return 1;
00245 
00246 
00247         get_index_filename(source_filename, 
00248                 mwindow->preferences->index_directory, 
00249                 index_filename, 
00250                 asset->path);
00251 
00252 
00253 // Test for index in stream table of contents
00254         if(!source.get_index(index_filename))
00255         {
00256 printf("IndexFile::create_index 1\n");
00257                 redraw_edits(1);
00258         }
00259         else
00260 // Build index from scratch
00261         {
00262 
00263 
00264 
00265 
00266                 asset->index_zoom = get_required_scale(&source);
00267 
00268 // Indexes are now built for everything since it takes too long to draw
00269 // from CDROM source.
00270 
00271 
00272 // total length of input file
00273                 int64_t length_source = source.get_audio_length(0);  
00274 
00275 // get amount to read at a time in floats
00276                 int64_t buffersize = 65536;
00277                 char string[BCTEXTLEN];
00278                 sprintf(string, _("Creating %s."), index_filename);
00279 
00280                 progress->update_title(string);
00281                 progress->update_length(length_source);
00282                 redraw_timer->update();
00283 
00284 // thread out index thread
00285                 IndexThread *index_thread = new IndexThread(mwindow, 
00286                         this, 
00287                         asset, 
00288                         index_filename, 
00289                         buffersize, 
00290                         length_source);
00291                 index_thread->start_build();
00292 
00293 // current sample in source file
00294                 int64_t position = 0;
00295                 int64_t fragment_size = buffersize;
00296                 int current_buffer = 0;
00297 
00298 
00299 // pass through file once
00300                 while(position < length_source && !result)
00301                 {
00302                         if(length_source - position < fragment_size && fragment_size == buffersize) fragment_size = length_source - position;
00303 
00304                         index_thread->input_lock[current_buffer]->lock("IndexFile::create_index 1");
00305                         index_thread->input_len[current_buffer] = fragment_size;
00306 
00307                         int cancelled = progress->update(position);
00308                         if(cancelled || 
00309                                 index_thread->interrupt_flag || 
00310                                 interrupt_flag)
00311                         {
00312                                 result = 3;
00313                         }
00314 
00315                         for(int channel = 0; !result && channel < asset->channels; channel++)
00316                         {
00317                                 source.set_audio_position(position, 0);
00318                                 source.set_channel(channel);
00319 
00320 // Read from source file
00321                                 if(source.read_samples(index_thread->buffer_in[current_buffer][channel], 
00322                                         fragment_size,
00323                                         0)) result = 1;
00324                         }
00325 
00326 // Release buffer to thread
00327                         if(!result)
00328                         {
00329                                 index_thread->output_lock[current_buffer]->unlock();
00330                                 current_buffer++;
00331                                 if(current_buffer >= TOTAL_BUFFERS) current_buffer = 0;
00332                                 position += fragment_size;
00333                         }
00334                         else
00335                         {
00336                                 index_thread->input_lock[current_buffer]->unlock();
00337                         }
00338                 }
00339 
00340 // end thread cleanly
00341                 index_thread->input_lock[current_buffer]->lock("IndexFile::create_index 2");
00342                 index_thread->last_buffer[current_buffer] = 1;
00343                 index_thread->output_lock[current_buffer]->unlock();
00344 
00345                 index_thread->stop_build();
00346                 delete index_thread;
00347         }
00348 
00349 
00350         source.close_file();
00351 
00352 
00353         open_index(asset);
00354         close_index();
00355         mwindow->edl->set_index_file(asset);
00356 //printf("IndexFile::create_index 11\n");
00357         return 0;
00358 }
00359 
00360 
00361 int IndexFile::create_index(MWindow *mwindow, 
00362                 Asset *asset, 
00363                 MainProgressBar *progress)
00364 {
00365         return create_index(asset, progress);
00366 }
00367 
00368 
00369 
00370 int IndexFile::redraw_edits(int force)
00371 {
00372         int64_t difference = redraw_timer->get_scaled_difference(1000);
00373 
00374         if(difference > 250 || force)
00375         {
00376                 redraw_timer->update();
00377 // Can't lock window here since the window is only redrawn when the pixel
00378 // count changes.
00379                 mwindow->gui->lock_window("IndexFile::redraw_edits");
00380                 mwindow->edl->set_index_file(asset);
00381                 mwindow->gui->canvas->draw_indexes(asset);
00382                 asset->old_index_end = asset->index_end;
00383                 mwindow->gui->unlock_window();
00384         }
00385         return 0;
00386 }
00387 
00388 
00389 
00390 
00391 int IndexFile::draw_index(ResourcePixmap *pixmap, Edit *edit, int x, int w)
00392 {
00393 // check against index_end when being built
00394         if(asset->index_zoom == 0)
00395         {
00396                 printf(_("IndexFile::draw_index: index has 0 zoom\n"));
00397                 return 0;
00398         }
00399 
00400 // test channel number
00401         if(edit->channel > asset->channels) return 1;
00402 
00403 // calculate a virtual x where the edit_x should be in floating point
00404         double virtual_edit_x = 1.0 * edit->track->from_units(edit->startproject) * 
00405                         mwindow->edl->session->sample_rate /
00406                         mwindow->edl->local_session->zoom_sample - 
00407                         mwindow->edl->local_session->view_start;
00408 
00409 // samples in segment to draw relative to asset
00410         double asset_over_session = (double)edit->asset->sample_rate / 
00411                 mwindow->edl->session->sample_rate;
00412 //      int64_t startsource = (int64_t)(((pixmap->pixmap_x - pixmap->edit_x + x) * 
00413         int64_t startsource = (int64_t)(((pixmap->pixmap_x - virtual_edit_x + x) * 
00414                 mwindow->edl->local_session->zoom_sample + 
00415                 edit->startsource) * 
00416                 asset_over_session);
00417 // just in case we get a numerical error 
00418         if (startsource < 0) startsource = 0;
00419         int64_t length = (int64_t)(w * 
00420                 mwindow->edl->local_session->zoom_sample * 
00421                 asset_over_session);
00422 
00423         if(asset->index_status == INDEX_BUILDING)
00424         {
00425                 if(startsource + length > asset->index_end)
00426                         length = asset->index_end - startsource;
00427         }
00428 
00429 // length of index to read in samples * 2
00430         int64_t lengthindex = length / asset->index_zoom * 2;
00431 // start of data in samples
00432         int64_t startindex = startsource / asset->index_zoom * 2;  
00433 // Clamp length of index to read by available data
00434         if(startindex + lengthindex > asset->get_index_size(edit->channel))
00435                 lengthindex = asset->get_index_size(edit->channel) - startindex;
00436         if(lengthindex <= 0) return 0;
00437 
00438 
00439 
00440 
00441 // Actual length read from file in bytes
00442         int64_t length_read;   
00443 // Start and length of fragment to read from file in bytes.
00444         int64_t startfile, lengthfile;
00445         float *buffer = 0;
00446         int buffer_shared = 0;
00447         int i;
00448         int center_pixel = mwindow->edl->local_session->zoom_track / 2;
00449         if(mwindow->edl->session->show_titles) center_pixel += mwindow->theme->title_bg_data->get_h();
00450         int miny = center_pixel - mwindow->edl->local_session->zoom_track / 2;
00451         int maxy = center_pixel + mwindow->edl->local_session->zoom_track / 2;
00452         int x1 = 0, y1, y2;
00453 // get zoom_sample relative to index zoomx
00454         double index_frames_per_pixel = mwindow->edl->local_session->zoom_sample / 
00455                 asset->index_zoom * 
00456                 asset_over_session;
00457 
00458 // get channel offset
00459         startindex += asset->get_index_offset(edit->channel);
00460 
00461 
00462         if(asset->index_status == INDEX_BUILDING)
00463         {
00464 // index is in RAM, being built
00465                 buffer = &(asset->index_buffer[startindex]);
00466                 buffer_shared = 1;
00467         }
00468         else
00469         {
00470 // index is stored in a file
00471                 buffer = new float[lengthindex + 1];
00472                 buffer_shared = 0;
00473                 startfile = asset->index_start + startindex * sizeof(float);
00474                 lengthfile = lengthindex * sizeof(float);
00475                 length_read = 0;
00476 
00477                 if(startfile < file_length)
00478                 {
00479                         fseek(file, startfile, SEEK_SET);
00480 
00481                         length_read = lengthfile;
00482                         if(startfile + length_read > file_length)
00483                                 length_read = file_length - startfile;
00484 
00485                         fread(buffer, length_read + sizeof(float), 1, file);
00486                 }
00487 
00488                 if(length_read < lengthfile)
00489                         for(i = length_read / sizeof(float); 
00490                                 i < lengthfile / sizeof(float); 
00491                                 i++)
00492                                 buffer[i] = 0;
00493         }
00494 
00495 
00496 
00497         pixmap->canvas->set_color(mwindow->theme->audio_color);
00498 
00499 
00500         double current_frame = 0;
00501         float highsample = buffer[0];
00502         float lowsample = buffer[1];
00503         int prev_y1 = center_pixel;
00504         int prev_y2 = center_pixel;
00505         int first_frame = 1;
00506 
00507         for(int bufferposition = 0; 
00508                 bufferposition < lengthindex; 
00509                 bufferposition += 2)
00510         {
00511                 if(current_frame >= index_frames_per_pixel)
00512                 {
00513                         int next_y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
00514                         int next_y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
00515                         int y1 = next_y1;
00516                         int y2 = next_y2;
00517 
00518 // A different algorithm has to be used if it's 1 sample per pixel and the
00519 // index is used.  Now the min and max values are equal so we join the max samples.
00520                         if(mwindow->edl->local_session->zoom_sample == 1)
00521                         {
00522                                 pixmap->canvas->draw_line(x1 + x - 1, prev_y1, x1 + x, y1, pixmap);
00523                         }
00524                         else
00525                         {
00526 // Extend line height if it doesn't connect to previous line
00527                                 if(!first_frame)
00528                                 {
00529                                         if(y1 > prev_y2) y1 = prev_y2 + 1;
00530                                         if(y2 < prev_y1) y2 = prev_y1 - 1;
00531                                 }
00532                                 else
00533                                 {
00534                                         first_frame = 0;
00535                                 }
00536                                 pixmap->canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
00537                         }
00538                         current_frame -= index_frames_per_pixel;
00539                         x1++;
00540                         prev_y1 = next_y1;
00541                         prev_y2 = next_y2;
00542                         highsample = buffer[bufferposition];
00543                         lowsample = buffer[bufferposition + 1];
00544                 }
00545 
00546                 current_frame++;
00547                 highsample = MAX(highsample, buffer[bufferposition]);
00548                 lowsample = MIN(lowsample, buffer[bufferposition + 1]);
00549         }
00550 
00551 // Get last column
00552         if(current_frame)
00553         {
00554                 y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
00555                 y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
00556                 pixmap->canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
00557         }
00558 
00559 
00560 
00561 
00562         if(!buffer_shared) delete [] buffer;
00563         return 0;
00564 }
00565 
00566 int IndexFile::close_index()
00567 {
00568         if(file)
00569         {
00570                 fclose(file);
00571                 file = 0;
00572         }
00573 }
00574 
00575 int IndexFile::remove_index()
00576 {
00577         if(asset->index_status == INDEX_READY || asset->index_status == INDEX_NOTTESTED)
00578         {
00579                 close_index();
00580                 remove(index_filename);
00581         }
00582 }
00583 
00584 int IndexFile::read_info(Asset *test_asset)
00585 {
00586         if(!test_asset) test_asset = asset;
00587         if(test_asset->index_status == INDEX_NOTTESTED)
00588         {
00589 // read start of index data
00590                 fread((char*)&(test_asset->index_start), sizeof(int64_t), 1, file);
00591 
00592 // read test_asset info from index
00593                 char *data;
00594                 
00595                 data = new char[test_asset->index_start];
00596                 fread(data, test_asset->index_start - sizeof(int64_t), 1, file);
00597                 data[test_asset->index_start - sizeof(int64_t)] = 0;
00598                 FileXML xml;
00599                 xml.read_from_string(data);
00600                 test_asset->read(&xml);
00601 
00602                 delete [] data;
00603                 if(test_asset->format == FILE_UNKNOWN)
00604                 {
00605                         return 1;
00606                 }
00607         }
00608         return 0;
00609 }

Generated on Sun Jan 8 13:38:56 2006 for Cinelerra-svn by  doxygen 1.4.4