How to stretch to nearest or interpolate inbetween pixels in a logarithmic audio spectrum converted to a picture in Visual Studio using C# Console

Winston Conklin 0 Reputation points
2024-10-09T05:47:08.4433333+00:00

I'm trying to program a code to convert an audio to an image spectrogram in the scale of logarithmic, but black lines come up. I ask 4 different AI chatbots for help, and though it gave me some correct code, it gave wrong or broken code with this problem, and I am running out of options, and have no choice but to ask a human to help. Here is my code;

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using NAudio.Wave;
using MathNet.Numerics;
using MathNet.Numerics.IntegralTransforms;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;

class Program
{
    static void Main(string[] args)
    {
        
        string filePath = @"C:\Users\seven\Music\the-dentist-is-a-special-friend.wav";
        int fftLength = 4096; // FFT length

        
        string spectrogramPath = @"C:\Users\seven\Music\spectrogram.bmp"; // Path for the spectrogram image
        string modifiedSpectrogramPath = @"C:\Users\seven\Music\modified_spectrogram.bmp"; // Path for modified spectrogram

        using (var reader = new AudioFileReader(filePath))
        {
            var samples = new float[reader.Length / sizeof(float)];
            reader.Read(samples, 0, samples.Length);

            
            var spectrogram = GetLogSpectrogram(samples, reader.WaveFormat.SampleRate, fftLength);

            
            SaveSpectrogramImage(spectrogram, fftLength / 2, spectrogramPath);
        }

        
        ScalePart(@"C:\Users\seven\Music\spectrogram.bmp", modifiedSpectrogramPath);
    }

    static double[,] GetLogSpectrogram(float[] samples, int sampleRate, int fftLength)
    {
        int numSpectrogramRows = fftLength / 2;
        int numSpectrogramColumns = (samples.Length / fftLength) * 2;
        double[,] spectrogram = new double[numSpectrogramRows, numSpectrogramColumns];

        for (int i = 0; i < numSpectrogramColumns; i++)
        {
            int offset = i * fftLength / 2;
            if (offset + fftLength >= samples.Length)
                break;

            var buffer = samples.Skip(offset).Take(fftLength).Select(s => new Complex32(s, 0)).ToArray();
            Fourier.Forward(buffer, FourierOptions.NoScaling);

            for (int j = 0; j < numSpectrogramRows; j++)
            {
                spectrogram[j, i] = 20 * Math.Log10(Math.Max(buffer[j].Magnitude, 1e-10));
            }
        }

        return spectrogram;
    }

    static void SaveSpectrogramImage(double[,] spectrogram, int height, string outputPath)
    {
        int width = spectrogram.GetLength(1);
        using (Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb))
        {
            double max = spectrogram.Cast<double>().Max();
            double min = spectrogram.Cast<double>().Min();
            double gamma = 3;

            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    int value = (int)((spectrogram[y, x] - min) / (max - min) * 255);
                    value = (int)(255 * Math.Pow(value / 255.0, gamma)); // Apply gamma correction
                    System.Drawing.Color color = System.Drawing.Color.FromArgb(value, value, value);
                    bitmap.SetPixel(x, height - y - 1, color);
                }
            }

            bitmap.Save(outputPath, ImageFormat.Bmp);
        }
    }

    static void ScalePart(string inputPath, string outputPath)
    {
        using (var image = SixLabors.ImageSharp.Image.Load<Rgba32>(inputPath))
        {
            int originalHeight = image.Height;

            using (var outputImage = new Image<Rgba32>(image.Width, originalHeight))
            {
                for (int x = 0; x < image.Width; x++)
                {
                    for (int y = 0; y < originalHeight; y++)
                    {
                        double logScaleY = Math.Log(y + 1) / Math.Log(originalHeight + 1); // Normalized logarithm
                        int newY = (int)(logScaleY * (originalHeight - 1)); // Transform Y to new position

                        if (newY < originalHeight)
                        {
                            var color = image[x, originalHeight - y - 1]; // The image is flipped for coordinate compatibility
                            outputImage[x, newY] = color;
                        }
                    }
                }
                   outputImage.Save(outputPath);
            }
        }
    }
}

User's image

The black bars at the top I want removed, either by interpolating inbetween lines or stretching the nearest pixel vertically.

AI was giving me such a hard time, I am asking at after 1:45AM for help after a day and a half (give or take the breaks) barely getting it to work at all, even with an alternative, FFMPEG.

This is possible, right? Because Image Editors can pixelate or interpolate pictures. What is the full code (In this message and what I am trying to achieve)?

If you want to know, I am trying to convert a sound to a logarithmic frequency scale in an image, flip it vertically, redo the frequency, and convert it back to audio, so the pitch is reversed. Many AIs said I could shift the pitch, or resample, or reverse, or flip linearly (Hertz), or use Invert to flip the waveform, but that is not what I want. I basically want to invert the pitch.

These lines might result in additional weird sound, but I want to remove these black stripes and just flip it logarithmically.

Help would be appreciated. If this is the wrong category, please move it to the appropriate category and give me a link to the new path. If someone asked the same thing, please link me there, but I doubt someone asked this question because the AIs programming might not have what I am asking, because nobody is asking.

Quote Mark; Because reverse is slower than forward; it is speed in the negative.

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,989 questions
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.