Author Topic: The ChannelGetLevel() issue  (Read 9852 times)

3delite

  • Posts: 907
The ChannelGetLevel() issue
« on: 10 Nov '05 - 14:19 »
 
Came up with an idea!
Storing the position before and adjusting it back there after seems working:
 
Code: [Select]
    if (Streams.PlayingIndex <> '') then begin
        if BASS_ChannelIsActive(Channel) = BASS_ACTIVE_PLAYING then begin
            if SettingsWindow.RadioButtonASIO.Checked
                then PrevPos := BASS_ChannelGetPosition(Channel);
            lev := BASS_ChannelGetLevel(Channel);
            if SettingsWindow.RadioButtonASIO.Checked
                then BASS_ChannelSetPosition(Channel, PrevPos);
            TrackBarDigVolumeL.SelStart := 100 - Round(LoWord(lev) * 0.0030517578125);
            TrackBarDigVolumeR.SelStart := 100 - Round(HiWord(lev) * 0.0030517578125);
        end;
    end;

Are there any sidenotes I should know, or is this kinda ok way? :)
 
EDIT: BASS's CPU usage has grown into the skies. :) No it's not good. All the vis plugins don't work (so as all Sonique plugins) becouse they interfere with the mixer channel.
Well it looks like I have to give up implementig ASIO output into MP3 Stream Editor.
At least for now. ::)
 
« Last Edit: 10 Nov '05 - 14:51 by 3delite »

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: The ChannelGetLevel() issue
« Reply #1 on: 10 Nov '05 - 16:49 »
As you have noticed, seeking after every decode is not a very efficient thing to do. It also might not be possible at all, eg. when streaming internet radio.

There are other solutions to your problem. For example, you can buffer the decoded data in a DSP callback function, and then use that buffered data in BASS_ChannelGetLevel/Data calls via a custom decoding stream...

Code: [Select]
BYTE *buffer_data;
int buffer_len;
HSTREAM buffer_channel;

void CALLBACK BufferDSPProc(HDSP handle, DWORD channel, BYTE *buffer, DWORD length, DWORD user)
{
if (length>buffer_len) { // restrict to buffer length
buffer+=length-buffer_len;
length=buffer_len;
} else if (length!=buffer_len) // shift old data
memmove(buffer_data, buffer_data+length, buffer_len-length);
memcpy(buffer_data+buffer_len-length, buffer, length); // copy data to buffer
}

DWORD CALLBACK BufferStreamProc(HSTREAM handle, void *buffer, DWORD length, DWORD user)
{
if (length>buffer_len) length=buffer_len; // restrict to buffer length
memcpy(buffer, buffer_data+buffer_len-length, length); // copy data from buffer
return length;
}

...

// create custom decoding stream of the same format
BASS_CHANNELINFO i;
BASS_ChannelGetInfo(channel, &i);
if (BASS_GetConfig(BASS_CONFIG_FLOATDSP)) i.flags|=BASS_SAMPLE_FLOAT;
buffer_channel=BASS_StreamCreate(i.freq, i.chans, i.flags, BufferStreamProc, 0);

// allocate buffer (big enough for 4096 sample FFT)
buffer_len=4096*i.chans*sizeof(float);
buffer_data=malloc(buffer_len);
BASS_ChannelSetDSP(channel, (DSPPROC*)BufferDSPProc, 0, 0); // set the buffering DSP

...

level=BASS_ChannelGetLevel(buffer_channel); // get the level

When you're done with the channel, you should of course free the buffer (buffer_data) and stream (buffer_channel).

I've not tested this code, so there may be some silly typos or whatever, but the theory should be fine. You could wrap it up in a class/structure, to easily support multiple channels.

3delite

  • Posts: 907
Re: The ChannelGetLevel() issue
« Reply #2 on: 10 Nov '05 - 19:12 »
 
It's not good! Storing another channel is too complicated (I have to manage one more channel handle and I can't really afford it all plugins must be rebuilt), and I don't see how would be they in sync. I have to play this custom stream in the meantime with volume 0? And they will be in sync?
I would consider it tough, to implement if I am really sure it will work.

I'll think about it! If anyone's intrested here you can download the alpha ASIO enabled MP3SE.exe. Enable debug mode in settings!
« Last Edit: 11 Nov '05 - 18:28 by 3delite »

3delite

  • Posts: 907
Re: The ChannelGetLevel() issue
« Reply #3 on: 11 Nov '05 - 09:11 »
 
I tried understanding what happens in the callback functions, with no luck. Can somebody comment it a bit?

Thanks in advance!
 

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: The ChannelGetLevel() issue
« Reply #4 on: 11 Nov '05 - 14:58 »
It's not good! Storing another channel is too complicated (I have to manage one more channel handle and I can't really afford it all plugins must be rebuilt), and I don't see how would be they in sync. I have to play this custom stream in the meantime with volume 0? And they will be in sync?
I would consider it tough, to implement if I am really sure it will work.

I think you may have misunderstood what the code is doing. You don't play the buffer stream (buffer_channel). You just use it for your vis stuff, eg. BASS_ChannelGetLevel/Data calls. The rest of your code should pretty much remain untouched. You may want to clear the buffer (buffer_data) after seeking/pausing/stopping, but that's about it :)

3delite

  • Posts: 907
Re: The ChannelGetLevel() issue
« Reply #5 on: 11 Nov '05 - 17:22 »
 
The problem is it still won't solve the problems related to vis plugins like bass_vis.dll etc.
I will have to wait for a function like BASS_ASIO_ChannelPlay() like the older brother BASS_ChannelPlay() so that data is buffered and all the extra addons work fine.

Thanks for help anyway, if somebody would explain what the callback functions exactly do, I would be gratefull, that buffering thing... :-[
 
I dont't understand how will it be in the same position as my source stream. ???
 
« Last Edit: 11 Nov '05 - 18:41 by 3delite »

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: The ChannelGetLevel() issue
« Reply #6 on: 13 Nov '05 - 14:08 »
The problem is it still won't solve the problems related to vis plugins like bass_vis.dll etc.

BASS_VIS uses BASS_ChannelGetData, so it should work fine - you just use the buffer stream handle (buffer_handle) in the function calls.

3delite

  • Posts: 907
Re: The ChannelGetLevel() issue
« Reply #7 on: 13 Nov '05 - 15:14 »
 
I leave that for tomorrow, becouse I have other problems too. There is one plugin that I can not rebuild, I used some functions that disapeared and I can't rebuild it.
There are some crashes and hangs inside the callback functions with this ASIO mode also. The same code works ok, for regular channel handling but when it comes to being a decode stream for ASIO's custom stream, it hangs. For now I get more problems than problems solved with ASIO. But I look forward to it's development! :)
 
« Last Edit: 13 Nov '05 - 15:28 by 3delite »

Chris

  • Posts: 1810
Re: The ChannelGetLevel() issue
« Reply #8 on: 17 Dec '05 - 13:33 »
Hi
i have tried to convert that to delphi but will have same Probelms  the crash is gone but the result is wrong

Code: [Select]
var
  RecChan : HRecord;
  RecDSP : HDSP;
  Buffer_Channel: HSTREAM;
  Buffer_Data: PByte;
  Buffer_len: DWORD;

// callbacks

procedure BufferDSPProc(handle:HDSP; channel : DWORD; buffer: Pointer; length, user: DWORD); stdcall;
var
  b,b1,b2: PByte;
begin
  b := Buffer;
  b1 := Buffer_Data;
  b2 := Buffer_Data;

  if length > Buffer_len then
  begin
    inc(b, (Length-Buffer_len));
    length := Buffer_len;
   end else
   if length <> Buffer_len then
   begin
     inc(b1, Length);
     MoveMemory(Buffer_Data, b1, Buffer_len-Length);
   end;
      inc(b2, (Buffer_len - length));
      CopyMemory(b2, b, Length);
end;
Code: [Select]
function BufferStreamProc(handle: HSTREAM; buffer: Pointer; length, user: DWORD): DWORD; stdcall;
var
  b: PByte;
begin
  b := Buffer_Data;
  if length > buffer_len then
    length := Buffer_len;
    inc(b, (Buffer_len  - length));
    CopyMemory(Buffer, b, length);
   result := length;
end;
Code: [Select]
procedure StartRecording;
var
  i: BASS_CHANNELINFO;
begin
  RecChan := BASS_RecordStart(44100, 2, 0, nil, 0);
  if RecCHan = 0 then exit;
    // okay letz buffered the RecChan
  BASS_ChannelGetInfo(bass_record.RecChan, i) ;
  if BASS_GetConfig(BASS_CONFIG_FLOATDSP) = BASS_CONFIG_FLOATDSP then
      i.flags := i.flags or BASS_SAMPLE_FLOAT;
      buffer_channel := BASS_StreamCreate(i.freq, i.chans, i.flags, @BufferStreamProc, 0);
      // allocate buffer (big enough for 4096 sample FFT)
      buffer_len := 4096 * i.chans * sizeof(float);
      Getmem(buffer_data, buffer_len);
      RecDSP := BASS_ChannelSetDSP(Bass_record.RecChan, @BufferDSPProc, 0, 0); // set the buffering DSP
end;


Any Ideas ?? btw or is it a better Idea to set BufferDSPProc inside a RecordingCallback ??

Greets Chris
« Last Edit: 20 Dec '05 - 22:52 by Chris »

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: The ChannelGetLevel() issue
« Reply #9 on: 18 Dec '05 - 14:25 »
There's a little bug/typo in your conversion here...

Code: [Select]
     MoveMemory(Buffer_Data, b1, Buffer_len+Length);
It should be Buffer_len-Length ... see if that helps :)

Chris

  • Posts: 1810
Re: The ChannelGetLevel() issue
« Reply #10 on: 18 Dec '05 - 20:41 »
Hi
sorry ,no its the same Result......  looks like that the MoveMemory will crash

Here the Dr Watson Log

http://www.cst-development.de/bass_samples/buffered_error.txt

Greets Chris
« Last Edit: 18 Dec '05 - 20:49 by Chris »

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: The ChannelGetLevel() issue
« Reply #11 on: 19 Dec '05 - 14:14 »
Yep, looks like the source address and length are fine, but the destination probably isn't... I don't use Delphi, so this is just a guess, but are you sure the '@' is needed in front of Buffer_Data? After all, Buffer_Data is a pointer, and so are b/b1/b2.

Chris

  • Posts: 1810
Re: The ChannelGetLevel() issue
« Reply #12 on: 19 Dec '05 - 23:41 »
Hi
nope without the @ it canīt work....
maybe the buffer_data must be an array ???
if possible can you make a little demo in c/c++ ???
to see if it work....
Thanks
Greets Chris...

radio42

  • Posts: 4576
Re: The ChannelGetLevel() issue
« Reply #13 on: 20 Dec '05 - 11:42 »
Just had a chat with Chirs...I guess now I understand your issue (I hope):

-> You want to get the (peak)Level for a recording channel - right?
...so that you can show it on a VU-meter etc.?!

But why making it so complicated with a buffered new stream?
Just don't use BASS_ChannelGetData!

I simply calculate the peak-level myself directly in the RECORDPROC callback!
Since here you already get the buffer with all needed sample data filled !
So there is no need to even call BASS_ChannelGetLevel - which will just steal data and will even be slower...
And the RECORDPROC is called often enough (default is 100ms, but you can adjusted that in your BASS_RecordStart call to e.g. 50ms).

So my RECORDPROC (in C#) looks like this to calculate the peaklevel and to display it...
Code: [Select]
private unsafe bool MyRecoring(int handle, IntPtr buffer, int length, int user)
{
// user will contain our encoding handle
if (length > 0 && buffer != IntPtr.Zero)
{
if (!this.buttonStartRec.Enabled)
{
// if recording started...write the data to the encoder
BassWma.BASS_WMA_EncodeWrite(user, buffer, length);
}
// get the rec level...
int maxL = 0;
int maxR = 0;
short *data = (short*)buffer;
for (int a = 0; a < length/2; a++)
{
// decide on L/R channel
if (a % 2 == 0)
{
// L channel
if (data[a] > maxL)
maxL = data[a];
}
else
{
// R channel
if (data[a] > maxR)
maxR = data[a];
}
}
// limit the maximum peak levels to 0bB = 32768
// the peak levels will be int values, where 32768 = 0dB!
if (maxL > 32768)
maxL = 32768;
if (maxR > 32768)
maxR = 32768;
this.progressBarRecL.Value = maxL;
this.progressBarRecR.Value = maxR;
}
return true; // always continue recording
}
P.S: Forget about the BASS_WMA_EncodeWrite call - it is just because here I also do the encoding of the recording to a WMA file;-)
« Last Edit: 20 Dec '05 - 11:44 by radio42 »

engineeer

  • Posts: 86
Re: The ChannelGetLevel() issue
« Reply #14 on: 20 Dec '05 - 20:36 »
nope without the @ it canīt work....
It can work - just replace ^Byte with PByte...

Chris

  • Posts: 1810
Re: The ChannelGetLevel() issue
« Reply #15 on: 21 Dec '05 - 00:56 »
Hi
@ Ian
PByte have solved the crash...
but Bass_ChannelGet Level will allways return -1
Bass_error get code will return 24 (BASS_ERROR_NOPLAY)
JOBnik! has try to build the the code in c++ (Many Thanks for that)
must the buffer_channel be played ????
Greets Chris
« Last Edit: 21 Dec '05 - 01:24 by Chris »

(: JOBnik! :)

  • Posts: 1065
Re: The ChannelGetLevel() issue
« Reply #16 on: 21 Dec '05 - 12:38 »
Hi ;D

Yep, as Chris wrote, we have tested the code yesterday and it seems that we got a -1 value with error code 24.

Then only if using BASS_ChannelPlay(buffer_channel, FALSE) could make it work, but it worked only in C++, in Delphi there was always a crash...

Any ideas? :)

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: The ChannelGetLevel() issue
« Reply #17 on: 21 Dec '05 - 14:09 »
This buffer stuff is meant for use with decoding channels, eg. when using BASSASIO. I don't think there's any reason to use it with normal playback (or recording) channels? :)

Chris

  • Posts: 1810
Re: The ChannelGetLevel() issue
« Reply #18 on: 21 Dec '05 - 14:24 »
Hi
okay thanks for the fast answer...
The Problem is/was...
a Record Channel ist not buffered...
so i was searching to find a way that bass_channelgetlevel will NOT steal the data from the record chan....
Greets Chris

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: The ChannelGetLevel() issue
« Reply #19 on: 21 Dec '05 - 14:27 »
If you use a RECORDPROC, it is buffered. Is there a reason you're not using a RECORDPROC?

Chris

  • Posts: 1810
Re: The ChannelGetLevel() issue
« Reply #20 on: 21 Dec '05 - 14:34 »
Ahhhhhhhhhh  I`m stupid......yes of cource..........
many thanks.......grrrrr  stupid flaw in reasoning of me.....
Greets Chris