Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 5966099
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 22, 20262026-05-22T19:44:42+00:00 2026-05-22T19:44:42+00:00

I used readData successfully to read 16-bit audio files and generate peak files for

  • 0

I used readData successfully to read 16-bit audio files and generate peak files for wave form display. However, I’m having some trouble interpreting PCM values for 24-bit FLAC and WAV files.

First, what is the block size for 24-bit?

16-bit signed values ranges from -32768 to +32768 and 24-bit ranges from -8388607 to +8388607.

I used 4096 bytes block size for 16-bit files (65536 / 16 = 4096). It works fine for detecting peaks.

If I do the same calculation with 24-bit, 16777215 / 24 = 699050.625 bytes. Am I mistaken? I guess I have to use 32-bit variables to store the 24-bit values. But what block size should I use when reading the file? 699051? How do I adjust the conversion to float arrays?

Here is the full C# code I’m using to generate peak files for 16-bit PCM data. I’ve left the 24-bit code empty on purpose since it doesn’t work. Some code references my own FMOD wrapper but it should be simple to understand.

 // Declare variables
            FMOD.RESULT result = FMOD.RESULT.OK;
            FileStream fileStream = null;
            BinaryWriter binaryWriter = null;
            GZipStream gzipStream = null;
            bool generatePeakFile = false;
            int CHUNKSIZE = 0;
            uint length = 0;
            uint read = 0;
            uint bytesread = 0;
            Int16[] left16BitArray = null;
            Int16[] right16BitArray = null;
            Int32[] left32BitArray = null;
            Int32[] right32BitArray = null;
            float[] floatLeft = null;
            float[] floatRight = null;
            byte[] buffer = null;
            IntPtr data = new IntPtr(); // initialized properly later
            WaveDataMinMax minMax = null;

            try
            {
                // Set current file directory
                m_peakFileDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\Peak Files\\";

                // Get file name from argument
                string fileName = (string)e.Argument;

                // Create sound system with NOSOUND
                MPfm.Sound.System soundSystem = new MPfm.Sound.System(FMOD.OUTPUTTYPE.NOSOUND, string.Empty);

                // Create sound
                MPfm.Sound.Sound sound = soundSystem.CreateSound(fileName, false);

                // Get sound format; specifically bits per sample (changes the calculations later)
                SoundFormat soundFormat = sound.GetSoundFormat();

                // Get the length of the file in PCM bytes               
                sound.BaseSound.getLength(ref length, FMOD.TIMEUNIT.PCMBYTES);

                // Check if the folder for peak files exists
                if (!Directory.Exists(PeakFileDirectory))
                {
                    // Create directory
                    Directory.CreateDirectory(PeakFileDirectory);
                }

                // Generate the file name for the peak file by using the full path without special characters
                string peakFilePath = PeakFileDirectory + fileName.Replace(@"\", "_").Replace(":", "_").Replace(".", "_") + ".mpfmPeak";

                // Check if peak file exists                
                if(!File.Exists(peakFilePath))
                {
                    // Set flag
                    generatePeakFile = true;

                    // Create peak file
                    fileStream = new FileStream(peakFilePath, FileMode.Create, FileAccess.Write);
                    binaryWriter = new BinaryWriter(fileStream);
                    gzipStream = new GZipStream(fileStream, CompressionMode.Compress);                   
                }

                // Check the bits per sample to determine what chunk size to get                
                if (soundFormat.BitsPerSample == 16)
                {
                    // 4096 bytes for 16-bit PCM data
                    CHUNKSIZE = 4096;
                }
                else if (soundFormat.BitsPerSample == 24)
                {
                    // 699050.625 bytes for 24-bit PCM data (???)   
                    CHUNKSIZE = 699051;
                }

                // Create buffer
                data = Marshal.AllocHGlobal(CHUNKSIZE);
                buffer = new byte[CHUNKSIZE];

                // Loop through file using chunk size
                do
                {
                    // Check for cancel
                    if (m_workerWaveForm.CancellationPending)
                    {
                        return;
                    }

                    // Check the bits per sample
                    if (soundFormat.BitsPerSample == 16)
                    {
                        // Read data chunk (4096 bytes for 16-bit PCM data)
                        result = sound.BaseSound.readData(data, (uint)CHUNKSIZE, ref read);
                        Marshal.Copy(data, buffer, 0, CHUNKSIZE);
                        bytesread += read;

                        // Is freehglobal needed? it crashes after one use.
                        //Marshal.FreeHGlobal(data);

                        // Convert the byte (8-bit) arrays into a short (16-bit) arrays (signed values)
                        left16BitArray = new Int16[buffer.Length / 4];
                        right16BitArray = new Int16[buffer.Length / 4];

                        // Loop through byte (8-bit) array buffer; increment by 4 (i.e. 4 times more data in 16-bit than 8-bit)
                        for (int i = 0; i < buffer.Length; i = i + 4)
                        {
                            // Convert values to 16-bit
                            left16BitArray[i / 4] = BitConverter.ToInt16(buffer, i);
                            right16BitArray[i / 4] = BitConverter.ToInt16(buffer, i + 2); // alternate between left and right channel
                        }

                        // Convert the short arrays to float arrays (signed values)
                        // This will convert the -32768 to 32768 value range to -1 to 1 (useful for wave display) 
                        floatLeft = new float[left16BitArray.Length];
                        floatRight = new float[left16BitArray.Length];
                        for (int i = 0; i < left16BitArray.Length; i++)
                        {
                            // 16-bit data for unsigned values range from 0 to 65536.
                            floatLeft[i] = left16BitArray[i] / 65536.0f;
                            floatRight[i] = right16BitArray[i] / 65536.0f;                            
                        }
                    }
                    else if (soundFormat.BitsPerSample == 24)
                    {
                       // (non-working code removed)

                        // (I have no idea if this works) Convert the short arrays to float arrays (signed values)
                        // This will convert the -8388608 to 8388608value range to -1 to 1 (useful for wave display) 
                        floatLeft = new float[left32BitArray.Length];
                        floatRight = new float[left32BitArray.Length];
                        for (int i = 0; i < left32BitArray.Length; i++)
                        {
                            // 16-bit data for unsigned values range from 0 to 16777215.
                            floatLeft[i] = left32BitArray[i] / 16777215.0f;
                            floatRight[i] = right32BitArray[i] / 16777215.0f;                            
                        }
                    }

                    // Calculate min/max
                    minMax = AudioTools.GetMinMaxFromWaveData(floatLeft, floatRight, false);
                    WaveDataHistory.Add(minMax);

                    // Report progress
                    m_bytesRead = bytesread;
                    m_totalBytes = length;
                    m_percentageDone = ((float)bytesread / (float)length) * 100;

                    // Write peak information to hard disk
                    if (generatePeakFile)
                    {
                        // 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);
                    }                  
                }
                while (result == FMOD.RESULT.OK && read == CHUNKSIZE);

                // Release sound from memory
                sound.Release();

                // Close sound system and release from memory
                soundSystem.Close();
                soundSystem.Release();

                // Set nulls for garbage collection               
                sound = null;
                soundSystem = null;
                left16BitArray = null;
                right16BitArray = null;
                left32BitArray = null;
                right32BitArray = null;
                floatLeft = null;
                floatRight = null;                
                buffer = null;
                minMax = null;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                // Did we have to generate a peak file?
                if (generatePeakFile)
                {
                    // Close writer and stream
                    gzipStream.Close();
                    binaryWriter.Close();                   
                    fileStream.Close();

                    // Set nulls
                    gzipStream = null;
                    binaryWriter = null;
                    fileStream = null;
                }
            }

            // Call garbage collector
            GC.Collect();

Here is the method that extracts the min/max values from float arrays:

/// <summary>
/// This method takes the left channel and right channel wave raw data and analyses it to get
/// the maximum and minimum values in the float structure. It returns a data structure named
/// WaveDataMinMax (see class description for more information). Negative values can be converted to
/// positive values before min and max comparaison. Set this parameter to true for output meters and
/// false for wave form display controls.
/// </summary>
/// <param name="waveDataLeft">Raw wave data (left channel)</param>
/// <param name="waveDataRight">Raw wave data (right channel)</param>
/// <param name="convertNegativeToPositive">Convert negative values to positive values (ex: true when used for output meters, 
/// false when used with wave form display controls (since the negative value is used to draw the bottom end of the waveform).<</param>
/// <returns>WaveDataMinMax data structure</returns>
public static WaveDataMinMax GetMinMaxFromWaveData(float[] waveDataLeft, float[] waveDataRight, bool convertNegativeToPositive)
{
    // Create default data
    WaveDataMinMax data = new WaveDataMinMax();

    // Loop through values to get min/max
    for (int i = 0; i < waveDataLeft.Length; i++)
    {
        // Set values to compare
        float left = waveDataLeft[i];
        float right = waveDataRight[i];

        // Do we have to convert values before comparaison?
        if (convertNegativeToPositive)
        {
            // Compare values, if negative then remove negative sign
            if (left < 0)
            {
                left = -left;
            }
            if (right < 0)
            {
                right = -right;
            }
        }

        // Calculate min/max for left channel
        if (left < data.leftMin)
        {
            data.leftMin = left;
        }
        if (left > data.leftMax)
        {
            data.leftMax = left;
        }

        // Calculate min/max for right channel
        if (right < data.rightMin)
        {
            data.rightMin = right;
        }
        if (right > data.rightMax)
        {
            data.rightMax = right;
        }

        // Calculate min/max mixing both channels
        if (left < data.mixMin)
        {
            data.mixMin = left;
        }
        if (right < data.mixMin)
        {
            data.mixMin = right;
        }
        if (left > data.mixMax)
        {
            data.mixMax = left;
        }
        if (right > data.mixMax)
        {
            data.mixMax = right;
        }
    }

    return data;
}

Can anybody give me a hint on what to do? I hope my code isn’t too bad and be can used as an example for 16-bit files. Thanks for any help!

EDIT:

Here is the 3×8-bit to 24-bit using a 32-bit variable conversion code:

                left32BitArray = new Int32[buffer.Length / 6];
                right32BitArray = new Int32[buffer.Length / 6];
                for (int i = 0; i < buffer.Length; i = i + 6)
                {
                        // Create smaller array in order to add the 4th 8-bit value
                        byte[] byteArrayLeft = new byte[4] {buffer[i], buffer[i + 1], buffer[i + 2], 0 };
                        byte[] byteArrayRight = new byte[4] { buffer[i + 3], buffer[i + 4], buffer[i + 5], 0 };

                        // Convert values to 32-bit variables
                        left32BitArray[i / 6] = BitConverter.ToInt32(byteArrayLeft, 0);
                        right32BitArray[i / 6] = BitConverter.ToInt32(byteArrayRight, 0);
                }
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-22T19:44:44+00:00Added an answer on May 22, 2026 at 7:44 pm

    24 bit audio files have a block align of 3 * number of channels. Why not go for 100ms of audio:

    int blockSize = 3 * channels * (sampleRate / 10);
    

    This will work fine for 24 bit WAV. Whether or not your FLAC reader lets you read out to that granularity depends on its internal implementation.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'm trying to read a process memory using the following code: void readdata(HANDLE phandle,
We used the undocumented xp_fileexist stored procedure for years in SQL Server 2000 and
I used the LINQ to SQL designer in Visual Studio to create an object
Never used a cache like this before. The problem is that I want to
I used to work in a place where a common practice was to use
I used jQuery to set hover callbacks for elements on my page. I'm now
When used like this: import static com.showboy.Myclass; public class Anotherclass{} what's the difference between
We used to use SourceSafe, and one thing I liked about it was that
I used to be able to do the following in Preview 3 <%=Html.BuildUrlFromExpression<AController>(c =>
I used to work with eclipse for nearly all the languages I need. I'm

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.