20 May '13 - 21:58 *
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: BASS_ChannelGetData problem on certain mp3  (Read 1075 times)
Harvy
Posts: 8


« on: 25 Mar '12 - 08:25 »
Reply with quoteQuote

Hello,

Given this code :

int stream = Bass.BASS_StreamCreateFile(file, 0, 0, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_PRESCAN | BASSFlag.BASS_SAMPLE_MONO);
long streamLength = Bass.BASS_ChannelGetLength(stream, 0);
float[] levels = new float[2];
int spectrumSize = 512;
int maxFFT = (int)(BASSData.BASS_DATA_FFT1024);

long position = 0;
while (position < streamLength)
{
     float[] d = new float[spectrumSize];
     Bass.BASS_ChannelGetData(stream, d, maxFFT);
     posTofftData.Add(d);
     position = Bass.BASS_ChannelGetPosition(stream);
}

For a certain MP3, the position does not advance from 37494784 to 37495296. So I get a memory overflow (the d array is initialized in a while (true). Any ideas? Who needs, I can give the mp3 (it's too big to attach it here). Thank you.

Sincerely,
Andrei Neagu
Logged
Harvy
Posts: 8


« Reply #1 on: 25 Mar '12 - 10:07 »
Reply with quoteQuote

An a second question:

I do not know how BASS_ChannelGetData provides the data:

on an aprox 400 sec length mp3 file:
If I give BASS_DATA_FFT4096, then I get 4241 arrays of 2048 and a big spectrum of frequencies (2048 frequencies)
If I give BASS_DATA_FFT256, then I get more than 67841 arrays of 128 and a smaller spectrum of frequencies (128 frequencies)

1) From what I understand, getting data with BASS_ChannelGetData advances the song. Why does it advance differently in these 2 cases?
2) How can I get more arrays with BASS_DATA_FFT4096? Is it possible without setting the position in song? Is there any way to get BASS_DATA_FFT4096 on a fixed number of msec from a song? (Ex: I want the BASS_DATA_FFT4096 on 20 msec sections of a song). I may need more data on less timespan. 4096 gives around 10 arrays/second, I may need more than that.
3) The values in the float arrays returned, are the intensity of the frequency? I get the frequency using Utils.FFTIndex2Frequency.

Sincerely,
Andrei Neagu

PS: If you don't have time to explain, any links will be appreciated. From the documentation, I didn't understand these things. (Don't have any background on signal processing or stuff like that). Thank you.
Logged
Ian @ un4seen
Administrator
Posts: 15253


« Reply #2 on: 26 Mar '12 - 16:42 »
Reply with quoteQuote

while (position < streamLength)
{
     float[] d = new float[spectrumSize];
     Bass.BASS_ChannelGetData(stream, d, maxFFT);
     posTofftData.Add(d);
     position = Bass.BASS_ChannelGetPosition(stream);
}

For a certain MP3, the position does not advance from 37494784 to 37495296. So I get a memory overflow (the d array is initialized in a while (true). Any ideas? Who needs, I can give the mp3 (it's too big to attach it here). Thank you.

What line does the problem occur at? I'm not a .Net user myself, so I'm not certain how things work there, but perhaps the problem is the "new" call in the loop? There is no real need for that to be inside the loop (unless it's needed by the "posTofftData.Add" line?), so you could try moving it outside the loop, eg. to just before the "while" line. If the problem still happens, also try using BASS_ChannelIsActive (rather than the position) to detect when the end is reached, like this...

float[] d = new float[spectrumSize];
while (Bass.BASS_ChannelIsActive(stream))
{
     Bass.BASS_ChannelGetData(stream, d, maxFFT);
     posTofftData.Add(d);
}

I do not know how BASS_ChannelGetData provides the data:

on an aprox 400 sec length mp3 file:
If I give BASS_DATA_FFT4096, then I get 4241 arrays of 2048 and a big spectrum of frequencies (2048 frequencies)
If I give BASS_DATA_FFT256, then I get more than 67841 arrays of 128 and a smaller spectrum of frequencies (128 frequencies)

1) From what I understand, getting data with BASS_ChannelGetData advances the song. Why does it advance differently in these 2 cases?

That is because different amounts of sample data are required for the different FFT sizes, ie. BASS_DATA_FFT4096 requires 4096 samples from the stream, while BASS_DATA_FFT256 requires 256 samples.

2) How can I get more arrays with BASS_DATA_FFT4096? Is it possible without setting the position in song? Is there any way to get BASS_DATA_FFT4096 on a fixed number of msec from a song? (Ex: I want the BASS_DATA_FFT4096 on 20 msec sections of a song). I may need more data on less timespan. 4096 gives around 10 arrays/second, I may need more than that.

No, you would need to set the position (via BASS_ChannelSetPosition) before each BASS_ChannelGetData call in that case.

3) The values in the float arrays returned, are the intensity of the frequency? I get the frequency using Utils.FFTIndex2Frequency.

Each FFT bin/value contains the amplitude of (or close to) the frequency given by FFTIndex2Frequency in the stream. For example, if the stream has a 1000 Hz tone with an amplitude of 0.5, then the FFT bin corresponding to 1000 Hz will have an ampitude of 0.5 (may be slightly lower if 1000 Hz isn't the bin's centre frequency).
Logged
Harvy
Posts: 8


« Reply #3 on: 26 Mar '12 - 23:23 »
Reply with quoteQuote


What line does the problem occur at? I'm not a .Net user myself, so I'm not certain how things work there, but perhaps the problem is the "new" call in the loop? There is no real need for that to be inside the loop (unless it's needed by the "posTofftData.Add" line?), so you could try moving it outside the loop, eg. to just before the "while" line. If the problem still happens, also try using BASS_ChannelIsActive (rather than the position) to detect when the end is reached, like this...

float[] d = new float[spectrumSize];
while (Bass.BASS_ChannelIsActive(stream))
{
     Bass.BASS_ChannelGetData(stream, d, maxFFT);
     posTofftData.Add(d);
}

Well, the problem was that the combination Bass.BASS_ChannelGetData(stream, d, maxFFT); and Bass.BASS_ChannelGetPosition(stream); did not advance the stream (maybe a bug?). That caused the new float[] to kill the memory.

anyway, I changed the code to:
            double totalTime = Bass.BASS_ChannelBytes2Seconds(stream, streamLength);
            double timeSpan = IndexTimeSpan;
            double currentTime = 0;

            try
            {
                while (currentTime < totalTime)
                {
                    float[] d = new float[spectrumSize];
                    Bass.BASS_ChannelSetPosition(stream, currentTime);
                    Bass.BASS_ChannelGetData(stream, d, maxFFT);
                    posTofftData.Add(d);

                    currentTime += timeSpan;
                }
            }
            finally
            {
                Bass.BASS_StreamFree(stream);
            }

The BASS_ChannelIsActive returns 4 possible values (BASS_ACTIVE_STOPPED, BASS_ACTIVE_PLAYING, BASS_ACTIVE_STALLED, BASS_ACTIVE_PAUSED). The while (Bass.BASS_ChannelIsActive(stream)) should be while (Bass.BASS_ChannelIsActive(stream) == BASSActive.BASS_ACTIVE_PLAYING) ?

That is because different amounts of sample data are required for the different FFT sizes, ie. BASS_DATA_FFT4096 requires 4096 samples from the stream, while BASS_DATA_FFT256 requires 256 samples.
No, you would need to set the position (via BASS_ChannelSetPosition) before each BASS_ChannelGetData call in that case.
Each FFT bin/value contains the amplitude of (or close to) the frequency given by FFTIndex2Frequency in the stream. For example, if the stream has a 1000 Hz tone with an amplitude of 0.5, then the FFT bin corresponding to 1000 Hz will have an ampitude of 0.5 (may be slightly lower if 1000 Hz isn't the bin's centre frequency).

Thank you.

Other questions:
1) do you have a sample code that will generate a new mp3 based on an existing mp3? I want to generate 10 sec mp3s from existing ones.
2) Is there any function that will generate a background noise?

Thank you!

Sincerely,
Andrei Neagu
Logged
Harvy
Posts: 8


« Reply #4 on: 26 Mar '12 - 23:33 »
Reply with quoteQuote

Another thing:

Let's say I use BASSData.BASS_DATA_FFT16384 with the BASS_ChannelGetData. Let's say that this will advance the song by 300 ms.
The 1000Hz FFT bin will have am amplitude of 0.5. This 0.5 means that the steam processed had a medium amplitude of 0.5 for the 1000Hz tone (for 150 msec the 1000 Hz tone had an amplitude of 0.7, for the other 150 msec had an amplitude of 0.3 => a medium amplitude of 0.5)? Or that at a certain point in this 300 ms stream, there was a tone with an amplitude of 0.5 and 1000Hz?

Thank you!

Sincerely,
Andrei Neagu
Logged
Ian @ un4seen
Administrator
Posts: 15253


« Reply #5 on: 27 Mar '12 - 17:17 »
Reply with quoteQuote

Well, the problem was that the combination Bass.BASS_ChannelGetData(stream, d, maxFFT); and Bass.BASS_ChannelGetPosition(stream); did not advance the stream (maybe a bug?). That caused the new float[] to kill the memory.

Do you mean it stopped advancing once it reached a certain point? BASS_ChannelGetData will definitely advance the stream's position, but perhaps the end of the file was reached earlier than expected and that resulted in it never leaving the "while (position < streamLength)" loop. Using BASS_ChannelIsActive will avoid that possibility as it will leave the loop when the end is reached, no matter what position that happens to be at.

1) do you have a sample code that will generate a new mp3 based on an existing mp3? I want to generate 10 sec mp3s from existing ones.

You can do that by creating a decoding channel (BASS_STREAM_DECODE flag) and setting an MP3 encoder (eg. LAME) on it via the BASSenc add-on (BASS_Encode_Start), and then processing 10 seconds of data before closing the encoder. Something like this...

BASS_Encode_Start(stream, "lame - 10sec.mp3", 0, NULL, 0); // set an MP3 encoder (LAME) on the stream
DWORD todo=BASS_ChannelSeconds2Bytes(stream, 10); // 10s of data in bytes
while (todo && BASS_ChannelIsActive(stream) && BASS_Encode_IsActive(stream)) {
BYTE buf[20000]; // processing buffer
DWORD r=BASS_ChannelGetData(stream, buf, min(todo, sizeof(buf))); // process some data
if (r==(DWORD)-1) break; // error
todo-=r; // count down
}
BASS_Encode_Stop(stream); // close the encoder

2) Is there any function that will generate a background noise?

BASS won't generate noises, but you can generate and play any noise that you want via a custom stream (see BASS_StreamCreate).

Let's say I use BASSData.BASS_DATA_FFT16384 with the BASS_ChannelGetData. Let's say that this will advance the song by 300 ms.
The 1000Hz FFT bin will have am amplitude of 0.5. This 0.5 means that the steam processed had a medium amplitude of 0.5 for the 1000Hz tone (for 150 msec the 1000 Hz tone had an amplitude of 0.7, for the other 150 msec had an amplitude of 0.3 => a medium amplitude of 0.5)? Or that at a certain point in this 300 ms stream, there was a tone with an amplitude of 0.5 and 1000Hz?

The former, ie. 0.5 would be the average for that 16384 sample block (the samples in the middle of the block will have more bearing than those at the ends by default due to the window function).
Logged
Harvy
Posts: 8


« Reply #6 on: 28 Mar '12 - 22:46 »
Reply with quoteQuote

Do you mean it stopped advancing once it reached a certain point? BASS_ChannelGetData will definitely advance the stream's position, but perhaps the end of the file was reached earlier than expected and that resulted in it never leaving the "while (position < streamLength)" loop. Using BASS_ChannelIsActive will avoid that possibility as it will leave the loop when the end is reached, no matter what position that happens to be at.

Ok. thanks Smiley

You can do that by creating a decoding channel (BASS_STREAM_DECODE flag) and setting an MP3 encoder (eg. LAME) on it via the BASSenc add-on (BASS_Encode_Start), and then processing 10 seconds of data before closing the encoder. Something like this...

BASS_Encode_Start(stream, "lame - 10sec.mp3", 0, NULL, 0); // set an MP3 encoder (LAME) on the stream
DWORD todo=BASS_ChannelSeconds2Bytes(stream, 10); // 10s of data in bytes
while (todo && BASS_ChannelIsActive(stream) && BASS_Encode_IsActive(stream)) {
BYTE buf[20000]; // processing buffer
DWORD r=BASS_ChannelGetData(stream, buf, min(todo, sizeof(buf))); // process some data
if (r==(DWORD)-1) break; // error
todo-=r; // count down
}
BASS_Encode_Stop(stream); // close the encoder

Ok, thanks. I managed to do it:

if (!Un4seen.Bass.AddOn.Enc.BassEnc.LoadMe())
    throw new Exception(Bass.BASS_ErrorGetCode().ToString());

.......................................

public void GenerateMp3(string fromFile, string lameStuff, int secStart, int time)
        {
            int newStream  = Bass.BASS_StreamCreateFile(fromFile, 0, 0, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_MONO);
            var err = BassEnc.BASS_Encode_Start(newStream, lameStuff,
                Un4seen.Bass.AddOn.Enc.BASSEncode.BASS_ENCODE_AUTOFREE | BASSEncode.BASS_ENCODE_MONO, null, System.IntPtr.Zero);
            Bass.BASS_ChannelSetPosition(newStream, secStart);
            int todo = Convert.ToInt32(Bass.BASS_ChannelSeconds2Bytes(newStream, time)); // 10s of data in bytes
            while (todo > 0 && Bass.BASS_ChannelIsActive(newStream) == BASSActive.BASS_ACTIVE_PLAYING &&
                BassEnc.BASS_Encode_IsActive(newStream) == BASSActive.BASS_ACTIVE_PLAYING)
                {
            byte[] buf = new byte[20000]; // processing buffer
                long r = Bass.BASS_ChannelGetData(newStream, buf, Math.Min(todo, Convert.ToInt32(buf.Length))); // process some data
            if (r == -1) break; // error
            todo-= Convert.ToInt32(r); // count down
            }
            BassEnc.BASS_Encode_Stop(newStream);
        }

BASS won't generate noises, but you can generate and play any noise that you want via a custom stream (see BASS_StreamCreate).

What I want is to combine the 10 sec mp3 with a generated noise mp3. Can I do this? Can you point me to the right methods or give some sample code? Thanks.

The former, ie. 0.5 would be the average for that 16384 sample block (the samples in the middle of the block will have more bearing than those at the ends by default due to the window function).

Ok. thanks

Sincerely,
Andrei Neagu
Logged
Ian @ un4seen
Administrator
Posts: 15253


« Reply #7 on: 29 Mar '12 - 14:27 »
Reply with quoteQuote

What I want is to combine the 10 sec mp3 with a generated noise mp3. Can I do this? Can you point me to the right methods or give some sample code? Thanks.

Do you mean you want to mix the 2 MP3 files and create another MP3 file from the mix? If so, I think the easiest way to do it would be with the BASSmix add-on: create a mixer (BASS_Mixer_StreamCreate), plug both MP3s into it (BASS_Mixer_StreamAddChannel), and then use the code above on the mixer, eg. set the encoder on the mixer.
Logged
Harvy
Posts: 8


« Reply #8 on: 15 Jun '12 - 08:52 »
Reply with quoteQuote

Hello,

Just another small question. What is the measurement system for the amplitude returned by BASS_ChannelGetData()? Is it Watt?

Thank you.
Logged
Ian @ un4seen
Administrator
Posts: 15253


« Reply #9 on: 15 Jun '12 - 14:26 »
Reply with quoteQuote

It would be volts. If you would like to use decibels (dBV), you can do so like this...

db=20*log10(fft[x]);
Logged
Harvy
Posts: 8


« Reply #10 on: 18 Jun '12 - 20:10 »
Reply with quoteQuote

Ok. Thanks alot!
Logged
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.18 | SMF © 2013, Simple Machines