Author Topic: ChannelGetData() problems  (Read 5368 times)

3delite

  • Posts: 926
ChannelGetData() problems
« on: 26 Oct '05 - 22:25 »
I do the following: Create a decoding channel, apply a BASS_FX Equalizer and my Normlize volume DSP, and in the third DSP I save all the data, something starts skipping. The resulting file is about 10 secs shorter.
I can write down the steps to repruduce the problem in MP3SE. If I apply only my Normalize DSP, the effect is less noticable. It's like there is problem if there is not enugh data in the buffer or something... ::)

EDIT: I was wrong. I save the decoding stream with ChannelGetData()! The saving is not in a DSP as I thought. :-X
But the problem is still there!

Here is the code (quite long sorry): ;)

Code: [Select]
procedure Stream(Channel: Cardinal; OutFilename: String);
var
  Stream: TFileStream;
  buf: array [0..102400] of DWORD;
  BytesRead, PercentDone, sIndex: integer;
  StartPos, StreamLength, StreamFrames: Int64;
  temp: string;
  ChanInfo: BASS_CHANNELINFO;
  wBitsPerSample: Word;
  nBlockAlign: Word;
  nChannels: Word;
  nSamplesPerSec: DWORD;
  nAvgBytesPerSec: DWORD;
  i: Integer;
  Subsong, Ending, res: Boolean;
  sBits, sName: String;
  ChanPosition: Int64;
  sync, status: Cardinal;
begin
    BytesRead := 1024 * 100; // 100kBytes
    Ending := False;
    Subsong := False;
    StartPos := 0;
    sIndex := MP3SEFuncs.StreamsFindStreamByChannel(Channel);

    sName := MP3SEFuncs.StreamsGetInfo(sIndex).Name;
    BASS_ChannelGetInfo(Channel, ChanInfo);
    StreamLength := BASS_ChannelGetLength(Channel);
       
    if sIndex > -1
        then StreamFrames := MP3SEFuncs.StreamsGetInfo(MP3SEFuncs.StreamsFindRootStream(sName)).Length
        else StreamFrames := Trunc(BASS_ChannelBytes2Seconds(Channel, BASS_ChannelGetLength(Channel)) / 0.026);
    if Copy(sName, 1, 1) = '.' then begin
        Subsong := True;
        StartPos := StrToInt(Copy(sName, 2, Pos('@', sName) - 2));
        StartPos := Round(((StartPos / 26) / StreamFrames) * StreamLength);
        StreamLength := BASS_ChannelSeconds2Bytes(Channel, (MP3SEFuncs.StreamsGetInfo(sIndex).PlayTime) / 1000);
    end;
    try
        FormInfo.CancelOp := False;
        Stream := TFileStream.Create(OutFilename, fmCreate);
        //*  WAV header
        temp := 'RIFF'; Stream.write(temp[1], length(temp));
        temp := #0#0#0#0; Stream.write(temp[1], length(temp));   // File size: to be updated
        temp := 'WAVE'; Stream.write(temp[1], length(temp));
        temp := 'fmt '; Stream.write(temp[1], length(temp));
        if (ChanInfo.flags AND BASS_SAMPLE_FLOAT) > 0 then begin
            temp := #$12#0#0#0; Stream.write(temp[1], length(temp));
            temp := #3#0; Stream.write(temp[1], length(temp));
            wBitsPerSample := 32;
        end else begin
            temp := #$10#0#0#0; Stream.write(temp[1], length(temp)); // Fixed
            temp := #1#0; Stream.write(temp[1], length(temp));       // PCM format
            wBitsPerSample := 16;
        end;
        nChannels := 0;
        case ChanInfo.chans of
            1: begin
                temp := #1#0;
                nChannels := 1;
            end;
            2: begin
                temp := #2#0;
                nChannels := 2;
            end;
            3: begin
                temp := #3#0;
                nChannels := 3;
            end;
            4: begin
                temp := #4#0;
                nChannels := 4;
            end;
        end; Stream.write(temp[1], length(temp));
        nBlockAlign := nChannels * wBitsPerSample div 8;
        nSamplesPerSec := Chaninfo.freq;
    nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
        Stream.write(nSamplesPerSec, 2);
        temp := #0#0; Stream.write(temp[1], length(temp));   // SampleRate is given as dWord
        Stream.write(nAvgBytesPerSec, 4);
        Stream.write(nBlockAlign, 2);
        Stream.write(wBitsPerSample, 2);
        if (ChanInfo.flags AND BASS_SAMPLE_FLOAT) > 0 then begin
            temp := #0#0; Stream.write(temp[1], length(temp));
        end;
        temp := 'data'; Stream.write(temp[1],length(temp));
        temp := #0#0#0#0; Stream.write(temp[1],length(temp)); // Data size: to be updated
        if (ChanInfo.flags AND BASS_SAMPLE_FLOAT) > 0
            then temp := #0#0#0#0; Stream.write(temp[1], length(temp));
        //* Stream it
        try
            BASS_ChannelRemoveSync(Channel, MP3SEFuncs.StreamsGetInfo(sIndex).SyncEnd);
            BASS_ChannelSetPosition(Channel, StartPos);
            if ChanInfo.flags AND BASS_CTYPE_MUSIC_MOD > 0 then begin
                while (BASS_ChannelIsActive(Channel) <> BASS_ACTIVE_STOPPED) do begin
                    BytesRead := 1024 * 100; // 100kBytes
                    try
                        BytesRead := BASS_ChannelGetData(Channel, @buf, BytesRead);
                    except
                        //*
                    end;
                    ChanPosition := BASS_ChannelGetPosition(Channel);
                    Stream.Write(buf, BytesRead);
                    PercentDone := Round(100 * Lo(BASS_ChannelGetPosition(Channel)) / BASS_ChannelGetLength(Channel));
                    Application.ProcessMessages;
                    if FormInfo.CancelOp
                        then Break;
                    if Assigned(FormInfo) then begin
                        FormInfo.Caption :=  IntToStr(PercentDone) + '% - Stream 32bit';
                        FormInfo.Gauge.Progress := PercentDone;
                    end;
                    MP3SEFuncs.SetProgress(PercentDone);
                end;
                PercentDone := 100;
            end else begin
                while (BASS_ChannelIsActive(Channel) <> BASS_ACTIVE_STOPPED) do begin
                    BytesRead := 1024 * 100; // 100kBytes
                    ChanPosition := BASS_ChannelGetPosition(Channel);
                    if ((ChanPosition + BytesRead) > (StartPos + StreamLength))
                    OR ((ChanPosition + BytesRead) > BASS_ChannelGetLength(Channel))
                    then begin
                        BytesRead := ((StartPos + StreamLength - 2) - ChanPosition);
                        Ending := True;
                    end;
                    try
                        BytesRead := BASS_ChannelGetData(Channel, @buf, BytesRead);
                    except
                        //*
                    end;
                    ChanPosition := BASS_ChannelGetPosition(Channel);

                    Stream.Write(buf, BytesRead);
                    PercentDone := Round(100 * ((ChanPosition - StartPos) / StreamLength));

                    Application.ProcessMessages;
                    if FormInfo.CancelOp
                        then Break;
                    if Assigned(FormInfo) then begin
                        FormInfo.Caption :=  IntToStr(PercentDone) + '% - Stream 32bit';
                        FormInfo.Gauge.Progress := PercentDone;
                    end;
                    MP3SEFuncs.SetProgress(PercentDone);

                    if Subsong
                    AND (ChanPosition > (StartPos + StreamLength))
                        then Break;

                    if Ending
                        then StreamFree(sIndex);
                end;
            end;
        finally
            // Rewrite some fields of header
            i := Stream.Size - 8;    // size of file
            Stream.Position := 4;
            Stream.write(i, 4);
            if (ChanInfo.flags AND BASS_SAMPLE_FLOAT) > 0 then begin
                i := i - $26;               // size of data
                Stream.Position := 42;
                sBits := '32';
            end else begin
                Stream.Position := 40;
                i := i - $24;
                sBits := '16';
            end;
            Stream.write(i, 4);
            Stream.Free;
            MP3SEFuncs.SetProgress(0);
            StreamFree(sIndex);
            MP3SEFuncs.Log('Plugin ' + PLUGIN_NAME + ' streamed ' + sBits + 'bit WAV: ' + OutFilename + ' ' + IntToStr(PercentDone) + '%', False);
        end;
    except
        on E: Exception do begin
            MP3SEFuncs.Log('Plugin: Stream 32bit Exception while streaming: ' + E.Message, True);
            MP3SEFuncs.Log('Check resulting WAV file''s validity! ~' + IntToStr(PercentDone) + '%', False);
            StreamFree(sIndex);
        end;
    end;   
end;

« Last Edit: 27 Oct '05 - 00:35 by 3delite »

Ian @ un4seen

  • Administrator
  • Posts: 21185
Re: ChannelGetData() problems
« Reply #1 on: 27 Oct '05 - 12:15 »
I do the following: Create a decoding channel, apply a BASS_FX Equalizer and my Normlize volume DSP, and in the third DSP I save all the data, something starts skipping. The resulting file is about 10 secs shorter.
I can write down the steps to repruduce the problem in MP3SE. If I apply only my Normalize DSP, the effect is less noticable. It's like there is problem if there is not enugh data in the buffer or something... ::)

EDIT: I was wrong. I save the decoding stream with ChannelGetData()! The saving is not in a DSP as I thought. :-X
But the problem is still there!

DSP functions have no effect on the amount of data you get from BASS_ChannelGetData.

Where is the data apparently being removed from, eg. start, end, all over the place? Does the problem stop if you remove your normalize DSP? If so, what does that function look like?

Also, can you reproduce the problem with the precompiled WRITEWAV example? (in C\BIN)

3delite

  • Posts: 926
Re: ChannelGetData() problems
« Reply #2 on: 28 Oct '05 - 15:41 »
DSP functions have no effect on the amount of data you get from BASS_ChannelGetData.
Well, that's my problem too! :)

Where is the data apparently being removed from, eg. start, end, all over the place? Does the problem stop if you remove your normalize DSP? If so, what does that function look like?
It's all over the place (jumps). But only if I apply the DSPs! That should not change the buffer length, shouldn't it?
How come that I apply a DSP and get less data? ::)

Also, can you reproduce the problem with the precompiled WRITEWAV example? (in C\BIN)
If I use the code from above without DSPs then it's ok.
I could write down the steps and you could check whats goin' on with a debug version of bass.dll!

Just tried with BASS FX Equalizer and BASS FX Phaser:
Source MP3: 8:15.67
Result WAV: 8:02.35
Very nasty eh? :)

If I don't use any DSPs then I get a little (2-3sec) difference only. There is something going on... Maybe my Stream 32bit WAV Plugin didn't work at all, all time! :-[

Just checked writewav and it's ok!

If I use my other Save As WAV... (inside MP3SE) that one is all right also. Something is not right with my above code, (or) but how comes that DSPs affect it?
 
« Last Edit: 28 Oct '05 - 16:59 by 3delite »

3delite

  • Posts: 926
Re: ChannelGetData() problems
« Reply #3 on: 28 Oct '05 - 17:39 »

I've got something!!! :)
If I take out the Application.ProcessMessages; line everything's fine.
Now that's a funny error! My only thoght is that my progress indicator slider was changing position just a little every now and then, and when DSPs were used the processing time was much longer and the slider (if it was his fault) moved a little more...
Just guessing...

Thanks for the help anyway!!! ;D

Ian @ un4seen

  • Administrator
  • Posts: 21185
Re: ChannelGetData() problems
« Reply #4 on: 29 Oct '05 - 14:26 »
I've got something!!! :)
If I take out the Application.ProcessMessages; line everything's fine.

Maybe you're calling BASS_ChannelGetData/Level on the same channel somewhere else, eg. in a timer? That would take data from the channel.

3delite

  • Posts: 926
Re: ChannelGetData() problems
« Reply #5 on: 29 Oct '05 - 15:05 »

Yes ChannelGetLevel() for the VU.
Why does it take data? I mean why doeas it change position? It should (as I see) only get level from the current position without advancing... no? :)

Ian @ un4seen

  • Administrator
  • Posts: 21185
Re: ChannelGetData() problems
« Reply #6 on: 30 Oct '05 - 14:20 »
Why does it take data? I mean why doeas it change position? It should (as I see) only get level from the current position without advancing... no? :)

But where is it getting the level from? :) ... Sample data. And if the channel is a decoding channel, that means it has to decode some (it isn't buffered). See how the CUSTLOOP example scans an entire file just using BASS_ChannelGetLevel.

3delite

  • Posts: 926
Re: ChannelGetData() problems
« Reply #7 on: 30 Oct '05 - 15:41 »

Well ok... ::)

3delite

  • Posts: 926
Re: ChannelGetData() problems
« Reply #8 on: 30 Oct '05 - 22:55 »
 
It would be cooler if there were one for advancing in the stream (ChannelGetData) and another for only peeking into it (ChannelGetLevel)! :)
How doeas it work? I mean if I am playing a stream and doing ChannelGetLevel it wouldn't skip there, would it?
 

Ian @ un4seen

  • Administrator
  • Posts: 21185
Re: ChannelGetData() problems
« Reply #9 on: 31 Oct '05 - 13:42 »
When you play a channel, there's a playback buffer, which the level can be taken from. There's no such buffer with decoding channels.

If you want to get the level while decoding/writing to disk, you could get it from the data you decoded.

3delite

  • Posts: 926
Re: ChannelGetData() problems
« Reply #10 on: 31 Oct '05 - 17:28 »
 
I see...
 
If you want to get the level while decoding/writing to disk, you could get it from the data you decoded.

It's not really needed, but would be cool if that worked seamlessly. The VU could alaways show whats happening with that channel.
Never mind. ;)
 

3delite

  • Posts: 926
Re: ChannelGetData() problems
« Reply #11 on: 1 Nov '05 - 02:04 »
 
Another mystery problem is solved!
That's way my ASIO Plugin wasn't working, when a stream was selected (and it's VU was shown)! :o
It was skipping!