/************************************************************************************** PROTUX - THE FREE PROFESSIONAL AUDIO TOOLS FOR LINUX AUTHOR : See AUTHORS file for details This software is distributed under the terms of the GNU General Public License as specified in the COPYING file. ***************************************************************************************/ #include #include #include #include #include "Audio.hh" #include "Peak.hh" #include // TODO : Sometimes the indexpointer of tempRAMBuffer exceeds the size of the array only with recorded audio. // This is some problem with the audioSource totalAudioBlocks?? const int Peak::MAX_ZOOM_USING_SOURCEFILE = 8; const int Peak::zoomStep[MAX_ZOOM_LEVELS] = { 1, 2, 4, 6, 8, 12, 16, 20, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 65536 }; Peak::Peak() { PENTERCONS; PEXITCONS; } Peak::~Peak() { PENTERDES; PEXITDES; } int Peak::build(Audio* anAudioSource, QProgressBar *monitorProgressBar ) { PENTER; audioSource = anAudioSource; audioSource->rewind_audio(); audioSourceFile = audioSource->get_file(); audioSourceFileSize = audioSource->get_file_size(); audioSize = audioSource->get_audio_size(); headerSize = audioSource->get_header_size(); blockSize = audioSource->get_block_size(); channels = audioSource->get_channels(); rate = audioSource->get_rate(); bitDepth = audioSource->get_bit_depth(); static const int MAX_CHANNELS=2; // FIX ME long long posInLevel [ MAX_ZOOM_LEVELS ]; long long totalAudioBlocks = (audioSize/blockSize); int tempStep=6; //important: do not change it into a value other then: 0, 1, 2, 4, 6. The lower this value, the more time is needed for the build process, but it is done more accurately (which doesn't make sense for the waveformcreation). totalRAMBufferSize=0; for (int hzoom = 0; hzoom0) { PMESG("Loaded peaks from previously saved image"); PEXIT; return 1; } // No saved peak. So it needs to re-scan the file MustuxLcd* lcd = audioSource->parentSong->get_default_lcd(); lcd->print("Rescanning Peaks : 0 %", 3); PMESG("Rescanning peaks"); qApp->processEvents(); QString afn = audioSource->get_filename(); long long blockPos = 0; long long stepInBytes; int ch = 0; long long pos = blockSize + headerSize; stepInBytes = blockSize * zoomStep[tempStep]; short* p = tempRAMBuffer; short sho; float f; //read peak information into tempRAMBuffer. do { fseek(audioSourceFile, pos, SEEK_SET); for (ch=0; chprint(si , 3, 20, false); if (monitorProgressBar) monitorProgressBar->setProgress(i); // This qApp->processEvents() below is to update Lcd, but it makes protux crashes. I left it commented, since it is less important right now. qApp->processEvents(); } } while ((blockPos < (totalAudioBlocks / zoomStep[tempStep])) && !feof(audioSourceFile)); int step; int posInTempBuffer; int matchedZoomLevel; short representativeSample; f = 60; //process the first 4 zoomlevels > MAX_ZOOM_USING_SOURCEFILE and place the values from tempRAMBuffer into RAMBUffer for (int hzoom=MAX_ZOOM_USING_SOURCEFILE+1; hzoom<13; hzoom++) { blockPos = 0; step = 0; do { for (ch=0; ch representativeSample) representativeSample = sho; posInTempBuffer += channels; } } long long pl = posInLevel [ matchedZoomLevel ]; RAMBuffer [ matchedZoomLevel ] [ pl ] = representativeSample; posInLevel [ matchedZoomLevel ]++; step++; } step += ((zoomStep[hzoom] * channels) / zoomStep[tempStep]) - channels; blockPos++; } while (blockPos < (totalAudioBlocks / zoomStep[hzoom])); f += 1.8181; int i = (int) f; QString si; si.setNum(i); lcd->print(si , 3, 20, false); if (monitorProgressBar) monitorProgressBar->setProgress(i); // This qApp->processEvents() below is to update Lcd, // but it makes protux crashes. I left it commented, since it // is less important right now. qApp->processEvents(); } tempStep = 11; //process the rest of the higher zoomlevels, but use values from zoomStep[11] which are already in RAMBuffer. //this step calculates 18 zoomlevels, and by using the RAMBuffer[zoomStep[11]] instead of tempRAMBuffer, //it reduces processing time for these zoomlevels at least 4 times. for (int hzoom=13; hzoom representativeSample) representativeSample = sho; posInTempBuffer += channels; } } long long pl = posInLevel [ matchedZoomLevel ]; RAMBuffer [ matchedZoomLevel ] [ pl ] = representativeSample; posInLevel [ matchedZoomLevel ]++; step++; } step += ((zoomStep[hzoom] * channels) / zoomStep [tempStep]) - channels; blockPos++; } while (blockPos < (totalAudioBlocks / zoomStep[hzoom])); f += 1.8181; int i = (int) f; QString si; si.setNum(i); lcd->print(si , 3, 20, false); if (monitorProgressBar) monitorProgressBar->setProgress(i); // This qApp->processEvents() below is to update Lcd, // but it makes protux crashes. I left it commented, since it // is less important right now. qApp->processEvents(); } delete tempRAMBuffer; lcd->print("Rescanning Peaks : 100 % .." , 3); if (monitorProgressBar) monitorProgressBar->setProgress(100); lcd->print("Rescanning Completed." , 4 ); PMESG("Rescanning Peaks : Completed."); if (save()<0) { PMESG("WARNING : Cannot save Peak image (RAM Buffers) to a peak file"); } PEXIT; return 1; } int Peak::unbuild() { fclose(audioSourceFile); for (int i=0; i MAX_ZOOM_USING_SOURCEFILE) { long long offsetInBytes = (startBlock / zoomStep[hzoom]) * blockSize; long long offsetInShorts = offsetInBytes / sizeof(short) ; short* pi = RAMBuffer[hzoom] + offsetInShorts; short* pf = RAMBuffer[hzoom] + RAMBufferSize[hzoom]; long long numShortsToFill = numBlocksToFill * channels; if (numShortsToFill >= (pf-pi)) numShortsToFill = pf-pi; if (numShortsToFill<0) return 0; memcpy(bufferToFill, pi, numShortsToFill*sizeof(short)); blocksFilled = numShortsToFill / channels; } else { long long stepInBytes = blockSize * zoomStep[hzoom]; long long pos = startBlock * blockSize + headerSize; long long originalPos = ftell(audioSourceFile); blocksFilled = 0; short sho; short* p = bufferToFill; do { fseek(audioSourceFile, pos, SEEK_SET); for (int ch=0; ch < channels; ch++) { fread(&sho, 1, sizeof(short), audioSourceFile); *(p++)=sho; } blocksFilled++; pos+=stepInBytes; } while ((blocksFilled < numBlocksToFill) && (!feof(audioSourceFile))); fseek(audioSourceFile, originalPos, SEEK_SET); } return blocksFilled; } void Peak::show_info() { PMESG("Peakfiles information\n"); for (int i=0; iMAX_ZOOM_USING_SOURCEFILE?"Using RAM buffer":"Using Source File") << "Peak step=" << zoomStep[i]); } } int Peak::save() { PENTER; QString peakFilename = audioSource->rootDir + "/"+audioSource->filename + ".peak"; PMESG("Saving Peak to %s", (const char*) peakFilename.latin1()); size_t size ; FILE* file = fopen((const char*)peakFilename.latin1(),"w+"); short* buf; if (!file) { PERROR("Cannot save Peak image to %s", (const char*) peakFilename.latin1()); PEXIT; return -1; } //store the values from RAMBuffer in a (temp) buf, and write buf at ones to the hard disk, delete buf afterwards. buf = (short*) malloc (totalRAMBufferSize*sizeof(short)); int pos=0; for (int hzoom = MAX_ZOOM_USING_SOURCEFILE+1; hzoomrootDir + "/"+ audioSource->filename + ".peak"; PMESG("Looking for peak image file %s", (const char*) peakFilename.latin1()); FILE* pfile = fopen((const char*)peakFilename.latin1(),"r+"); short* buf; if (!pfile) { PEXIT; return -1; } PMESG("Found it ! Loading it into RAM Buffers... "); //reading peakfile into (temp) buf, so the file reading can be done in one big slurp. buf = (short*) malloc (totalRAMBufferSize*sizeof(short)); fread(buf,sizeof(short),totalRAMBufferSize,pfile); int pos = 0; short sho; //putting the values in the right manner into RAMBuffer, deleting buf afterwards for (int hzoom = MAX_ZOOM_USING_SOURCEFILE+1; hzoom