Exemple #1
0
        /// <summary>
        /// Generates a peak file for an audio file.
        /// Note: BASS should be initialized already before calling this method. This uses a decode stream.
        /// </summary>
        /// <param name="audioFilePath">Audio file path</param>
        /// <param name="peakFilePath">Peak file path</param>
        public void GeneratePeakFile(string audioFilePath, string peakFilePath)
        {
#if ANDROID
            int[] buffer = null;
#else
            float[] buffer = null;
#endif


            bool cancelled = false;
            FileStream fileStream = null;
            BinaryWriter binaryWriter = null;
            GZipStream gzipStream = null;            
            int chunkSize = 0;
            int currentBlock = 0;
            long audioFileLength = 0;
            int read = 0;
            long bytesRead = 0;
            float[] floatLeft = null;
            float[] floatRight = null;
            IntPtr data = new IntPtr(); // initialized properly later
            WaveDataMinMax minMax = null;
            List<WaveDataMinMax> listMinMaxForProgressData = new List<WaveDataMinMax>();

            IsLoading = true;
            bool processSuccessful = false;
            _currentTask = Task.Factory.StartNew(() =>
            {
                try
                {
                    // Get audio file length and divide it by two since we're using floating point                     
                    Channel channelDecode = Channel.CreateFileStreamForDecoding(audioFilePath, _useFloatingPoint);
                    audioFileLength = channelDecode.GetLength();
                    audioFileLength /= 2;

                    // Delete any previous peak file
                    if (File.Exists(peakFilePath))
                        File.Delete(peakFilePath);

                    // Create streams and binary writer
                    fileStream = new FileStream(peakFilePath, FileMode.Create, FileAccess.Write);
                    binaryWriter = new BinaryWriter(fileStream);
                    gzipStream = new GZipStream(fileStream, CompressionMode.Compress);

                    // 4096 bytes for 16-bit PCM data
                    chunkSize = 4096;

                    // How many blocks will there be?                        
                    double blocks = Math.Ceiling(((double)audioFileLength / (double)chunkSize) * 2) + 1;

                    // Write file header (34 characters)                       
                    // 123456789012345678901234567890
                    // Sessions Peak File (version# 1.00)
                    string version = "Sessions Peak File (version# " + _version + ")";
                    binaryWriter.Write(version);

                    // Write audio file length
                    binaryWriter.Write(audioFileLength);
                    binaryWriter.Write((Int32)chunkSize);
                    binaryWriter.Write((Int32)blocks);                      

                    // Create buffer
                    data = Marshal.AllocHGlobal(chunkSize);

#if ANDROID
                    buffer = new int[chunkSize];
#else
                    buffer = new float[chunkSize];
#endif

                    // Is an event binded to OnProcessData?
                    if (OnProcessStarted != null)
                    {
                        PeakFileStartedData dataStarted = new PeakFileStartedData(){
                            Length = audioFileLength,
                            TotalBlocks = (Int32)blocks
                        };
                        OnProcessStarted(dataStarted);
                    }

                    // Loop through file using chunk size
                    int dataBlockRead = 0;
                    do
                    {
                        // Check for cancel
                        //Console.WriteLine("PeakFileService - Bytes read: " + bytesRead.ToString());
                        if (_cancellationToken.IsCancellationRequested)
                        {
                            // Set flags, exit loop
                            Console.WriteLine("PeakFileGenerator - Cancelling...");
                            cancelled = true;
                            IsLoading = false;
                            OnProcessDone(new PeakFileDoneData() { 
                                AudioFilePath = audioFilePath,
                                Cancelled = true
                            });
                            break;
                        }

                        // Get data and increment bytes read
                        read = channelDecode.GetData(buffer, chunkSize);
                        bytesRead += read;

                        // Create arrays for left and right channel
                        floatLeft = new float[chunkSize / 2];
                        floatRight = new float[chunkSize / 2];

                        // Loop through sample data to split channels
                        for (int a = 0; a < chunkSize; a++)
                        {
                            if (_useFloatingPoint)
                            {
                                // Check if left or right channel
                                if (a%2 == 0)
                                    floatLeft[a/2] = buffer[a];
                                else
                                    floatRight[a/2] = buffer[a];
                            }
                            else
                            {
#if ANDROID
                                // Get left/right channel values
                                short leftValue = Base.LowWord(buffer[a]);
                                short rightValue = Base.HighWord(buffer[a]);
                                floatLeft[a/2] = (float)leftValue / (float)Int16.MaxValue;
                                floatRight[a/2] = (float)rightValue / (float)Int16.MaxValue;
#endif
                            }
                        }

                        // Calculate min/max and add it to the min/max list for event progress
                        minMax = AudioTools.GetMinMaxFromWaveData(floatLeft, floatRight, false);                            
                        listMinMaxForProgressData.Add(minMax);

                        // Write peak information
                        binaryWriter.Write((double)minMax.leftMin);
                        binaryWriter.Write((double)minMax.leftMax);
                        binaryWriter.Write((double)minMax.rightMin);
                        binaryWriter.Write((double)minMax.rightMax);
                        binaryWriter.Write((double)minMax.mixMin);
                        binaryWriter.Write((double)minMax.mixMax);

                        // Update progress every X blocks (m_progressReportBlockInterval) default = 20
                        dataBlockRead += read;
                        if (dataBlockRead >= read * progressReportBlockInterval)
                        {
                            // Reset flag
                            dataBlockRead = 0;

                            // Report progress
                            PeakFileProgressData dataProgress = new PeakFileProgressData();
                            dataProgress.AudioFilePath = audioFilePath;
                            dataProgress.PeakFilePath = peakFilePath;
                            dataProgress.PercentageDone = (((float)bytesRead / (float)audioFileLength) / 2) * 100;
                            dataProgress.Length = audioFileLength;
                            dataProgress.CurrentBlock = currentBlock;
                            dataProgress.TotalBlocks = (Int32)blocks;
                            dataProgress.MinMax = listMinMaxForProgressData;
                            OnProcessData(dataProgress); 

                            // Reset min/max list
                            listMinMaxForProgressData = new List<WaveDataMinMax>();
                        }
                        currentBlock++;
                    } while (read == chunkSize);

                    // Free channel
                    Console.WriteLine("PeakFileService - Freeing channel...");
                    channelDecode.Free();

                    // TODO: This should replace the IsCancelled status since cancelling the task doesn't go end well
                    Console.WriteLine("PeakFileService - Is process successful? bytesRead: " + bytesRead.ToString() + " audioFileLength: " + audioFileLength.ToString());
                    if(bytesRead >= audioFileLength)
                        processSuccessful = true;

                    // Set nulls for garbage collection               
                    channelDecode = null;
                    floatLeft = null;
                    floatRight = null;
                    buffer = null;
                    minMax = null;
                } 
                catch (Exception ex)
                {
                    // Return exception
                    //e.Result = ex;
                    Console.WriteLine("PeakFileService - Error: " + ex.Message);
                } 
                finally
                {
                    // Close writer and stream
                    Console.WriteLine("PeakFileService - Closing file stream...");

                    if (gzipStream != null)
                        gzipStream.Close();
                    if (binaryWriter != null)
                        binaryWriter.Close();
                    if (fileStream != null)
                        fileStream.Close();

                    gzipStream = null;
                    binaryWriter = null;
                    fileStream = null;

                    // If the operation was cancelled, delete the files
                    if (cancelled)
                    {
                        // Check if file exists
                        if (File.Exists(peakFilePath))
                        {
                            try
                            {
                                // Delete file
                                File.Delete(peakFilePath);
                            } catch
                            {
                                // Just skip this step.
                                Tracing.Log("Could not delete peak file " + peakFilePath + ".");
                            }
                        }
                    }   
                }

                // Set completed
                IsLoading = false;
                Console.WriteLine("PeakFileService - ProcessDone - processSuccessful: " + processSuccessful.ToString() + " filePath: " + audioFilePath);
                OnProcessDone(new PeakFileDoneData() {
                    AudioFilePath = audioFilePath,
                    Cancelled = !processSuccessful
                });
            }, _cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);
        }
 void HandleOnPeakFileProcessStarted(PeakFileStartedData data)
 {
     //Console.WriteLine("WaveFormRenderingService - HandleOnPeakFileProcessStarted");
     OnGeneratePeakFileBegun(new GeneratePeakFileEventArgs());
 }