23 May '13 - 12:15 *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
 
   Home   Help Search Login Register  
Pages: [1]
  Reply  |  Print  
Author Topic: Truncate FX  (Read 711 times)
zburns
Posts: 5


« on: 15 May '12 - 22:01 »
Reply with quoteQuote

Just getting started and was looking for a routine to take audio from MP3 file, truncate any "noise" under an x db threashold (or something similar).  Is there quick way to do that.  I'd like to do it all in memory, then write out a new MP3 file (or I guess a WAV), then I can transcode that.

Zack
Logged
Ian @ un4seen
Administrator
Posts: 15269


« Reply #1 on: 16 May '12 - 15:11 »
Reply with quoteQuote

Are you looking to make nearly silent passages totally silent, or do you want to remove background noise? BASS doesn't include built-in support for either, but they could be implemented via DSP functions, ie. apply the appropriate processing to the sample data in the DSP function. The BASSenc add-on can be used to write the result to an MP3 file (with the LAME encoder). It could look something like this...

void CALLBACK MyDSP(HDSP handle, DWORD channel, void *buffer, DWORD length, void *user)
{
// process the sample data in "buffer" here
}

...

HSTREAM decoder=BASS_StreamCreateFile(FALSE, filename, 0, 0, BASS_STREAM_DECODE|BASS_SAMPLE_FLOAT); // create a "decoding channel" from the original file
BASS_ChannelSetDSP(decoder, MyDSP, 0, 0); // set a DSP function on it
BASS_Encode_Start(decoder, "lame - output.mp3", BASS_ENCODE_FP_24BIT|BASS_ENCODE_AUTOFREE, 0, 0); // set an MP3 encoder (LAME) on it too
// processing loop...
while (BASS_ChannelIsActive(decoder)) {
BYTE buf[20000]; // processing buffer
BASS_ChannelGetData(decoder, buf, sizeof(buf)); // process some data
}
BASS_StreamFree(decoder); // free the decoder (and encoder due to AUTOFREE)

Please see the documentation for details on the aforementioned functions.
Logged
gnag
Posts: 160


« Reply #2 on: 16 May '12 - 21:05 »
Reply with quoteQuote

When you have the sample data Buffer, you can use Utils.GetLevel to get a Level which is returned as an Integer between 0 and +32767. On that Integer you need to use Utils.HighWord for the Right Channel Level or Utils.LowWord for the Left Channel Level. The GetLevel call needs the Buffer as a Parameter to calculate the Level of the Sample Data it contains.

Using that Level you can for example calculate the Average of the Right&Left Channel Level and if it is for below a certain Value then you can count it as Silence. I am not sure about this Point, but I think you could let the DSP Callback return 0 to indicate that there are Zero Bytes so it will be truncated, maybe Ian can tell me if that would work ?
Logged
Ian @ un4seen
Administrator
Posts: 15269


« Reply #3 on: 17 May '12 - 15:39 »
Reply with quoteQuote

A DSPPROC function can't change the amount of sample data, only the content of the sample data. So if the aim is to remove blocks of data that are below a certain threshold, then that would need to be done outside of a DSP function, eg. in the processing loop. In that case, the encoding would need to be delayed too, until after the data has been processed. The code above could be modifed like this...

HSTREAM decoder=BASS_StreamCreateFile(FALSE, filename, 0, 0, BASS_STREAM_DECODE|BASS_SAMPLE_FLOAT); // create a "decoding channel" from the original file
BASS_Encode_Start(decoder, "lame - output.mp3", BASS_ENCODE_FP_24BIT|BASS_ENCODE_AUTOFREE|BASS_ENCODE_PAUSE, 0, 0); // set an MP3 encoder (LAME) on it and pause automated feeding
// processing loop...
while (BASS_ChannelIsActive(decoder)) {
float buf[5000]; // processing buffer
int r=BASS_ChannelGetData(decoder, buf, sizeof(buf)); // get some data
// process the sample data in "buf" here
BASS_Encode_Write(decoder, buf, r); // send the processed data to the encoder
}
BASS_StreamFree(decoder); // free the decoder (and encoder due to AUTOFREE)

In its simplest form, the processing to remove blocks of data below a threshold could look like this...

int r=BASS_ChannelGetData(decoder, buf, sizeof(buf)); // get some data
for (int a=0; a<r/sizeof(float); a++)
if (fabs(buf[a])>=threshold) { // at/above threshold
BASS_Encode_Write(decoder, buf, r); // send the data to the encoder
break;
}
Logged
zburns
Posts: 5


« Reply #4 on: 17 May '12 - 21:23 »
Reply with quoteQuote

I've attached a sample picture of my MP3 file, but yes, I'm attempting to truncate all the space.  What would threshold be in your exmple?




Here's my code - I was pretty close - currently writing to a WAV just to test it out, but something doesn't seem correct with the way I'm doing it.


static void Main(string[] args)
        {
            if (args.Length == 2)
            {
                int _inputfilestream = 0;
                int _outputfilehandle = 0;
                int THRESHOLD = ???;    //what should this be.

                Un4seen.Bass.BassNet.Registration("", "");
                Un4seen.Bass.BassNet.OmitCheckVersion = true;
                bool bassinit = Un4seen.Bass.Bass.BASS_Init(0, 22050, Un4seen.Bass.BASSInit.BASS_DEVICE_DEFAULT, System.IntPtr.Zero);
                if (bassinit == true)
                {
                    if (System.IO.File.Exists(args[0]))
                    {
                        _inputfilestream = Un4seen.Bass.Bass.BASS_StreamCreateFile(args[0], 0, 0, Un4seen.Bass.BASSFlag.BASS_STREAM_DECODE | Un4seen.Bass.BASSFlag.BASS_STREAM_PRESCAN | Un4seen.Bass.BASSFlag.BASS_SAMPLE_FLOAT);
                        if (_inputfilestream != 0)
                        {
                            byte[] buff = new byte[256];
                            int bytesread;
                            Un4seen.Bass.AddOn.Enc.BassEnc.BASS_Encode_Start(_inputfilestream, args[1] + ".wav", Un4seen.Bass.AddOn.Enc.BASSEncode.BASS_ENCODE_FP_24BIT | Un4seen.Bass.AddOn.Enc.BASSEncode.BASS_ENCODE_AUTOFREE | Un4seen.Bass.AddOn.Enc.BASSEncode.BASS_ENCODE_PCM | Un4seen.Bass.AddOn.Enc.BASSEncode.BASS_ENCODE_PAUSE, null, System.IntPtr.Zero);
                            while (Un4seen.Bass.Bass.BASS_ChannelIsActive(_inputfilestream) == Un4seen.Bass.BASSActive.BASS_ACTIVE_PLAYING)
                            {
                                bytesread = Un4seen.Bass.Bass.BASS_ChannelGetData(_inputfilestream, buff, buff.Length);
                                for (int a = 0; a < bytesread / sizeof(float); a++)
                                {
                                    //Console.WriteLine(Math.Abs(buff[a]));
                                    if (Math.Abs(buff[a]) >= THRESHOLD)  //at or above threshold
                                    {
                                        Un4seen.Bass.AddOn.Enc.BassEnc.BASS_Encode_Write(_inputfilestream, buff, bytesread);
                                        break;
                                    }
                                }
                            }
                            Un4seen.Bass.AddOn.Enc.BassEnc.BASS_Encode_Stop(_inputfilestream);
                        }
                        else
                        {
                            Console.WriteLine(Un4seen.Bass.Bass.BASS_ErrorGetCode().ToString());
                        }
                        Un4seen.Bass.Bass.BASS_StreamFree(_inputfilestream);
                    }
                    else
                    {
                        Console.WriteLine("Input File: \"" + args[0] + "\" is missing");
                    }
                }
                else
                {
                    Console.WriteLine("Error Initializing BASS.NET Library");
                }
                // free BASS
                Un4seen.Bass.Bass.BASS_Free();
            }
            else
            {
                Console.WriteLine("Usage: RemoveSilence inputfile.mp3 outputfile.mp3");
            }

* 05-17-2012 04-21-17.jpg (44.5 KB - downloaded 29 times.)
Logged
gnag
Posts: 160


« Reply #5 on: 17 May '12 - 22:17 »
Reply with quoteQuote

As you are using Floats (Un4seen.Bass.BASSFlag.BASS_SAMPLE_FLOAT) the buffer contains Values from -1 to +1 , so your THRESHOLD Variables needs to be of the type Float instead of Integer first !

Then just try increasing it until it meets your requirements, you could try for example 0.2. Take in mind that your Threshold Variable needs to be unsigned because of the applied Math.Abs.

Also I saw that you are using lots of encapsulated if instructions, this way your code becomes an unreadable chaos and therefore hard to debug, I suggest you to use break,return etc. instead.
Logged
zburns
Posts: 5


« Reply #6 on: 18 May '12 - 13:23 »
Reply with quoteQuote

That's just test code to see if I could get it to work - so it hasn't been refactored.

I do have BASS_SAMPLE_FLOAT set.  I tried thresholds from -1 to +1 (in steps of ".1") and it was the same every time.

One value did seem to truncate some at the beginning (about 5 minutes), but still silence after that.  The value....was "250" - kinda weird.
Logged
Ian @ un4seen
Administrator
Posts: 15269


« Reply #7 on: 18 May '12 - 14:54 »
Reply with quoteQuote

                            byte[] buff = new byte[256];

As gnag mentions, the sample data delivered by the BASS_ChannelGetData call will be 32-bit floating-point (due to the BASS_SAMPLE_FLOAT flag), so this should be a "float" array.

Regarding a threshold value, if you would like to use a decibel value, you can do so like this...

threshold=pow(10, db/20);
Logged
zburns
Posts: 5


« Reply #8 on: 18 May '12 - 15:45 »
Reply with quoteQuote

Duh, I totally missed that....I understand now....

I changed that to a FLOAT array, and tested all thresholds from -1 to 1 in .1 increments - no values seemed to work.  In fact values on the positive side of 0 created no data files what soever.  I must be missing something.

Is there a "for dummies" documentation on all this?  What's the difference between a "SAMPLE", "CHANNEL", etc, etc.

I'm not an audiophile at all.
Logged
Ian @ un4seen
Administrator
Posts: 15269


« Reply #9 on: 18 May '12 - 16:23 »
Reply with quoteQuote

The "threshold" variable should be a "float" with a value between 0 and 1. "0.1" could be a good starting point. If you still have any trouble with it, please post your updated code to see if there are any problems apparent in that.
Logged
zburns
Posts: 5


« Reply #10 on: 18 May '12 - 19:15 »
Reply with quoteQuote

Thanks Ian,

Update C# code as follows...warning - analyzes file 20 times just to find a good threshold (outer for loop) - currently not doing much of anything.

            if (args.Length == 2)
            {
                int _inputfilestream = 0;
                int _outputfilehandle = 0;
                float THRESHOLDMAX = 1;

                for (float THRESHOLD = -1; THRESHOLD < THRESHOLDMAX; THRESHOLD = THRESHOLD + 0.1f)
                {
                    Console.WriteLine("Trying THRESHOLD : " + THRESHOLD);
                    Un4seen.Bass.BassNet.Registration("", "");
                    Un4seen.Bass.BassNet.OmitCheckVersion = true;
                    bool bassinit = Un4seen.Bass.Bass.BASS_Init(0, 22050, Un4seen.Bass.BASSInit.BASS_DEVICE_DEFAULT, System.IntPtr.Zero);
                    if (bassinit == true)
                    {
                        if (System.IO.File.Exists(args[0]))
                        {
                            _inputfilestream = Un4seen.Bass.Bass.BASS_StreamCreateFile(args[0], 0, 0, Un4seen.Bass.BASSFlag.BASS_STREAM_DECODE | Un4seen.Bass.BASSFlag.BASS_STREAM_PRESCAN | Un4seen.Bass.BASSFlag.BASS_SAMPLE_FLOAT);
                            if (_inputfilestream != 0)
                            {
                                float[] buff = new float[256];
                                int bytesread;
                                Un4seen.Bass.AddOn.Enc.BassEnc.BASS_Encode_Start(_inputfilestream, args[1] + " THRESHOLD " + THRESHOLD + ".wav", Un4seen.Bass.AddOn.Enc.BASSEncode.BASS_ENCODE_FP_24BIT | Un4seen.Bass.AddOn.Enc.BASSEncode.BASS_ENCODE_AUTOFREE | Un4seen.Bass.AddOn.Enc.BASSEncode.BASS_ENCODE_PCM | Un4seen.Bass.AddOn.Enc.BASSEncode.BASS_ENCODE_PAUSE, null, System.IntPtr.Zero);
                                while (Un4seen.Bass.Bass.BASS_ChannelIsActive(_inputfilestream) == Un4seen.Bass.BASSActive.BASS_ACTIVE_PLAYING)
                                {
                                    bytesread = Un4seen.Bass.Bass.BASS_ChannelGetData(_inputfilestream, buff, buff.Length);
                                    for (int a = 0; a < bytesread / sizeof(float); a++)
                                    {
                                        //Console.WriteLine(Math.Abs(buff[a]));
                                        if (Math.Abs(buff[a]) >= THRESHOLD)  //at or above threshold
                                        {
                                            Un4seen.Bass.AddOn.Enc.BassEnc.BASS_Encode_Write(_inputfilestream, buff, bytesread);
                                            break;
                                        }
                                    }
                                }
                                Un4seen.Bass.AddOn.Enc.BassEnc.BASS_Encode_Stop(_inputfilestream);
                            }
                            else
                            {
                                Console.WriteLine(Un4seen.Bass.Bass.BASS_ErrorGetCode().ToString());
                            }
                            Un4seen.Bass.Bass.BASS_StreamFree(_inputfilestream);
                        }
                        else
                        {
                            Console.WriteLine("Input File: \"" + args[0] + "\" is missing");
                        }
                    }
                    else
                    {
                        Console.WriteLine("Error Initializing BASS.NET Library");
                    }
                    // free BASS
                    Un4seen.Bass.Bass.BASS_Free();
                }
            }
            else
            {
                Console.WriteLine("Usage: RemoveSilence inputfile.mp3 outputfile.mp3");
            }
Logged
Ian @ un4seen
Administrator
Posts: 15269


« Reply #11 on: 21 May '12 - 14:23 »
Reply with quoteQuote

That looks fine, except that the "THRESHOLD" value should always be above 0, ie. don't start the loop at -1. A threshold of 0 or below will mean that everything (including silence) passes it.

Also, I believe "buff.Length" will give you the number of elements in the "buff" array, rather than its byte size (as "sizeof" does). So you would probably want to change that line like this...

                                    bytesread = Un4seen.Bass.Bass.BASS_ChannelGetData(_inputfilestream, buff, buff.Length*sizeof(float));
Logged
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.18 | SMF © 2013, Simple Machines