private bool HasPotentialHumanSpeech(int visualChannel, long pos)
        {
            Bass.ChannelSetPosition(visualChannel, pos);

            const int scaleFactor  = _scaleFactorSqr * ushort.MaxValue;
            var       buffer       = new float[2048];
            var       bufferResult = _isMixerUsed
                ? BassMix.ChannelGetData(visualChannel, buffer, (int)_maxFft)
                : Bass.ChannelGetData(visualChannel, buffer, (int)_maxFft);

            var verticalSamplesWithSound = 0;

            if (bufferResult > 0)
            {
                for (var n = 0; n < buffer.Length; n++)
                {
                    // TODO: Don't convert to percentage, just check the threshold raw from the buffer
                    // TODO: Skip parts of the spectrogram that cannot be human speech
                    var percentage = (float)Math.Min(1d, Math.Sqrt(buffer[n]) * scaleFactor / ushort.MaxValue);
                    if (percentage > 0.35)
                    {
                        verticalSamplesWithSound++;
                        if (verticalSamplesWithSound > 4)
                        {
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
Example #2
0
        public override int GetData(float[] buffer)
        {
            var length = default(uint);

            switch (buffer.Length)
            {
            case 128:
                length = FFT256;
                break;

            case 256:
                length = FFT512;
                break;

            case 512:
                length = FFT1024;
                break;

            default:
                throw new NotImplementedException();
            }
            foreach (var channelHandle in this.MixerChannelHandles)
            {
                return(BassMix.ChannelGetData(channelHandle, buffer, unchecked ((int)length)));
            }
            return(0);
        }
Example #3
0
 public virtual int GetData(float[] buffer)
 {
     foreach (var channelHandle in this.GetMixerChannelHandles())
     {
         //Critical: BassMix.ChannelGetData will trigger an access violation in a random place if called concurrently with different buffer sizes. Yes this took a long time to work out.
         lock (ChannelDataSyncRoot)
         {
             return BassMix.ChannelGetData(channelHandle, buffer, buffer.Length);
         }
     }
     return 0;
 }
Example #4
0
        public virtual int GetData(float[] buffer, int fftSize)
        {
            var length = default(uint);

            switch (fftSize)
            {
            case BassFFT.FFT256:
                length = BassFFT.FFT256_MASK;
                break;

            case BassFFT.FFT512:
                length = BassFFT.FFT512_MASK;
                break;

            case BassFFT.FFT1024:
                length = BassFFT.FFT1024_MASK;
                break;

            case BassFFT.FFT2048:
                length = BassFFT.FFT2048_MASK;
                break;

            case BassFFT.FFT4096:
                length = BassFFT.FFT4096_MASK;
                break;

            case BassFFT.FFT8192:
                length = BassFFT.FFT8192_MASK;
                break;

            case BassFFT.FFT16384:
                length = BassFFT.FFT16384_MASK;
                break;

            case BassFFT.FFT32768:
                length = BassFFT.FFT32768_MASK;
                break;

            default:
                throw new NotImplementedException();
            }
            foreach (var channelHandle in this.GetMixerChannelHandles())
            {
                //Critical: BassMix.ChannelGetData will trigger an access violation in a random place if called concurrently with different buffer sizes. Yes this took a long time to work out.
                lock (ChannelDataSyncRoot)
                {
                    return(BassMix.ChannelGetData(channelHandle, buffer, unchecked ((int)length)));
                }
            }
            return(0);
        }
        private int DoWork(AudioVisualizer audioVisualizer, int visualChannel, Work queued, Rectangle clientRectangle)
        {
            var changes      = 0;
            var todoWorkList = SplitAndMerge(queued);

            var buffer = new float[2048]; // Move back inside loop if behavior is odd

            foreach (var work in todoWorkList)
            {
                try
                {
                    // TODO: Replace all this code with custom BASS_ChannelGetData instead, and paint a heatmap rather than a 3DVoicePrint
                    _maxFrequencySpectrum = FFTFrequency2Index(audioVisualizer.GetFrequencyRange(), 4096, 44100);

                    var clientXFrom = audioVisualizer.ByteIndexToClientX(work.From);
                    var clientXTo   = audioVisualizer.ByteIndexToClientX(work.To);
                    var clientWidth = (int)(clientXTo - clientXFrom);
                    if (clientWidth <= 0)
                    {
                        continue;
                    }

                    var bitmapWidth  = clientWidth;
                    var bitmapHeight = clientRectangle.Height;
                    var bitmap       = new DirectBitmap(bitmapWidth, bitmapHeight);
                    work.Bitmap = bitmap;
                    changes++;

                    var clipRectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
                    if (visualChannel == 0 || clipRectangle.Width <= 1 || clipRectangle.Height <= 1)
                    {
                        continue;
                    }

                    var bytesPerPixel = (double)(work.To - work.From) / bitmap.Width;

                    var verticalSamplesPerPixel = (double)_maxFrequencySpectrum / clipRectangle.Height;
                    var verticalSampleCount     = _maxFrequencySpectrum + 1;

                    const int scaleFactor = _scaleFactorSqr * ushort.MaxValue;

                    for (var pos = 0; pos < clipRectangle.Width; pos++)
                    {
                        Bass.ChannelSetPosition(visualChannel, (long)Math.Floor(work.From + pos * bytesPerPixel));

                        var bufferResult = _isMixerUsed
                            ? BassMix.ChannelGetData(visualChannel, buffer, (int)_maxFft)
                            : Bass.ChannelGetData(visualChannel, buffer, (int)_maxFft);

                        var y1      = 0;
                        var highest = 0f;

                        for (var index = 1; index < verticalSampleCount; ++index)
                        {
                            if (highest < buffer[index])
                            {
                                // By only printing the pixel if we've passed the current pixel's frequencies,
                                // and keeping the highest frequency of the pixel, we get a better representation.
                                highest = Math.Max(0, buffer[index]);
                            }

                            // TODO: Should not need to divide each time, should be able to increment on each loop.
                            var currentY = (int)(Math.Round(index / verticalSamplesPerPixel) - 1);
                            if (currentY > y1)
                            {
                                var dbIndex = bitmap.GetStartOffset(pos, y1);

                                // From near-purple blue (0.70) until red (0.0) in HSV hue wheel.
                                var percentage = Math.Min(1d, Math.Sqrt(highest) * scaleFactor / ushort.MaxValue);

                                var cacheIndex   = (int)Math.Floor((_cachedColors.Length - 1) * percentage);
                                var currentColor = _cachedColors[cacheIndex];

                                bitmap.Bits[dbIndex + 0] = currentColor.B; // B
                                bitmap.Bits[dbIndex + 1] = currentColor.G; // G
                                bitmap.Bits[dbIndex + 2] = currentColor.R; // R
                                bitmap.Bits[dbIndex + 3] = 255;            // A

                                y1      = currentY;
                                highest = 0;
                            }
                        }

                        if (pos < clipRectangle.Width - 1)
                        {
                            for (var y = 0; y < clipRectangle.Height; y++)
                            {
                                var dbIndex = bitmap.GetStartOffset(pos + 1, y);
                                bitmap.Bits[dbIndex + 0] = 0;
                                bitmap.Bits[dbIndex + 1] = 0;
                                bitmap.Bits[dbIndex + 2] = 0;
                                bitmap.Bits[dbIndex + 3] = 255;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }

            return(changes);
        }
Example #6
0
 public int ChannelGetData(IBassAudioChannel channel, float[] buffer, int length)
 => BassMix.ChannelGetData(channel.Handle, buffer, length);