WMA positioning fails????

Started by Ingolf,

Ingolf

Hi there,

I have a WMA decoding channel, which I read data from with a custom stream. Then when I try to set the position of the WMA channel using ChannelSetPosition, it returns true, but ErrorGetCode gives error code 25, not playing, and the music stops playing (ChannelGetData returns -1).

What does this mean, what could I be doing wrong? Is positioning the WMA channel only possible while playing?


Ian @ un4seen

You should be able to set the position on a decoding WMA channel too - I just tried it, and it was fine. Of course, you are using BASS_WMA_ChannelSetPosition? :)

Ingolf

Of course, sorry. I don't know what's happening... What does error code 25 mean? or any other ideas?

Irrational86

go through the header file (if using C/C++), through the PAS file (if using Delphi) or through the BAS file (if using VB) and you will find all error codes in there, this is the one that corresponds to 25:

BASS_ERROR_FREQ = 25;   // illegal sample rate

Ingolf

Yeah I already mentioned 25 = Not Playing, but i misread, indeed it is

  BASS_ERROR_FREQ         = 25;   // illegal sample rate

But then, why does this has anything to do with BASS_WMA_SetPosition, because I am certainly not changing any sample rate before calling it.

Ian @ un4seen

That's strange, BASSWMA never gives BASS_ERROR_FREQ. Please post the code you're using to create the stream, decode the stream, and change the position of the stream.

Ingolf

First, BASS_ErrorGetCode returns the last error code, so maybe SetPosition doesn't return 25, but a call made earlier by my program, maybe when it initializes. I'll have a look at it.

But that does not solve my problem. I read something about changing QWORD, but Delphi supports Int64.

I'll check my code, and send what I think is relevant...

Ingolf

My stream callback function to play the music:

function MusicStreamProc(Handle: HSTREAM; Buffer: Pointer; Length: DWORD; User: DWORD): DWORD; stdcall;
var
  A: PStreamData absolute User;
  Buf, Mix: Pointer;
  M, B: ^DWORD;
  I, pA, pB: Integer;
  aL, aR, bL, bR: SmallInt;
  Pri, Sec: Cardinal;
  EnoughData: Boolean;
begin
  Result := Length;
  B := Buffer;
  for I := 0 to (Length div 4)-1 do begin
    B^ := 0;
    Inc(B);
  end;

  if A.Playing then begin
    if A.Stream = bsPrimary then begin
      Pri := A.PriChan;
      Sec := A.SecChan;
    end
    else begin
      Pri := A.SecChan;
      Sec := A.PriChan;
    end;

    Buf := AllocMem(Length);
    Mix := AllocMem(Length);

    if A.PriStereo then pB := Length
    else pB := Length div 2;
    pA := BASS_ChannelGetData(Pri, Buf, pB);
    if A.Fading then BASS_ChannelGetData(Sec, Mix, pB);
    EnoughData := (pA = pB);

    if A.Fading then begin
      M := Mix;
      B := Buf;
      for I := 0 to (pA div 4)-1 do begin
        if EnoughData then begin
          aL := LoWord(B^);
          aR := HiWord(B^);
        end
        else begin
          aL := 0;
          aR := 0;
        end;
        bL := LoWord(M^);
        bR := HiWord(M^);
        aL := ClipSampleToInt((aL * A.FadingGain) + (bL * (1-A.FadingGain)));
        aR := ClipSampleToInt((aR * A.FadingGain) + (bR * (1-A.FadingGain)));
        B^ := MakeLong(aL, aR);
        if (A.PriStereo <> A.SecStereo) then begin
          if (not A.SecStereo) then begin
            if Odd(I) then Inc(M);
          end
          else Inc(M,2);
        end
        else Inc(M);
        Inc(B);
      end;
    end;

    if EnoughData then begin
      B := Buffer;
      M := Buf;
      for I := 0 to (Length div 4)-1 do begin
        if not A.PriStereo then begin
          B^ := MakeLong(M^,M^);
          Inc(B);
          B^ := MakeLong(M^,M^);
        end
        else B^ := M^;
        Inc(B);
        Inc(M);
      end;
    end;

    FreeMem(Buf);
    FreeMem(Mix);

    A.MusicPr^.ProcessAudio(Buffer, pA);
    if Assigned(A.OnWaveData) then A.OnWaveData(Buffer, pA);
  end;
end;

Method for creating the stream...

function TBassPlayer.LoadStream(FileOrUrl: String; CrossFade: Boolean): Boolean;
var
  F: PChar;
  NewType: TBassType;

  function CreateDec(var Dec: Cardinal): Boolean;
  begin
    Result := FALSE;
    if IsStream(FileOrUrl) then begin
      F := PChar(FileOrUrl);
      Dec := Bass_StreamCreateURL(F, 0, BASS_STREAM_META or BASS_STREAM_DECODE, nil);
      if Dec <> 0 then begin
        NewType := btInternet;
        Result := TRUE;
      end;
    end
    else begin
      F := PChar(FileOrUrl);
      FMetaTags.Text := '';
      Dec := Bass_WMA_StreamCreateFile(FALSE, F, 0, 0, BASS_STREAM_DECODE);
      if Dec = 0 then begin
        Dec := Bass_StreamCreateFile(False, F, 0, 0, BASS_STREAM_DECODE);
        if Dec <> 0 then begin
          FID3Tags := GetID3TagsData(BASS_StreamGetTags(Dec, BASS_TAG_ID3));
          if FID3Tags.Tag <> 'TAG' then begin
            FOggTags.Text := GetTagsData(BASS_StreamGetTags(Dec, BASS_TAG_OGG));
          end;
          NewType := btStream;
          Result := TRUE;
        end;
      end
      else begin
        FWMATags.Text := GetTagsData(BASS_WMA_StreamGetTags(Dec,0));
        NewType := btWMA;
        Result := TRUE;
      end;
    end;
  end;

var
  Vol: Cardinal;
  Pan: Integer;
begin
  InitBass;
  Result := FALSE;
  if CrossFade and (FLoadedStream <> '') then begin
    case FStream of
      bsPrimary:
        begin
          BASS_StreamFree(FSec);
          if CreateDec(FSec) then begin
            if FPaused then Stop;
            FStream := bsSecondary;
            FSecType := NewType;          
            Result := TRUE;
          end;
        end;
      bsSecondary:
        begin
          BASS_StreamFree(FPri);
          if CreateDec(FPri) then begin
            if FPaused then Stop;
            FStream := bsPrimary;
            FPriType := NewType;
            Result := TRUE;
          end;
        end;
    end;
    if Result then begin
      FStreamData.Fading := TRUE;
      FStreamData.FadingGain := 0;
      FCrossFadingPos := 0;
      FCrossFadingLastTick := GetTickCount;
    end;
  end
  else begin
    if FStream = bsSecondary then begin
      BASS_StreamFree(FSec);
      FStream := bsPrimary;
    end
    else BASS_StreamFree(FPri);
    Result := CreateDec(FPri);
    FPriType := NewType;
  end;
  if Result then begin
    if NewType = btInternet then begin
      UpdateIcyTags;
      FLastMeta := nil;
      UpdateMetaTags;
    end;
    if (not FDecodeOnly) then begin
      FStreamData.SecStereo := FStereo;
      FStreamData.SecIs8Bits := FIs8Bits;
      Bass_ChannelGetAttributes(GetStreamHandle, FBaseMusicFrequency, Vol, Pan);
      FStereo := (BASS_ChannelGetFlags(GetStreamHandle) and BASS_SAMPLE_MONO) = 0;
      FIs8Bits := (BASS_ChannelGetFlags(GetStreamHandle) and BASS_SAMPLE_8BITS) <> 0;
      FStreamData.MusicBaseFreq := FBaseMusicFrequency;
      FStreamData.PriStereo := FStereo;
      FStreamData.PriIs8Bits := FIs8Bits;
      FStreamData.PriChan := FPri;
      FStreamData.SecChan := FSec;
      FStreamData.Stream := FStream;
      FStreamData.BassType := FPriType;
      FStreamData.Playing := TRUE;
      InitBaseStream;
      if (FMusicBase = 0) then Result := FALSE
      else begin
        if not CrossFade then BASS_StreamPlay(FMusicBase,TRUE,0);
        MusicEQInitialize;
        FLoadedStream := FileOrUrl;
        SetMusicFrequency(FMusicFrequency);
      end;
    end
    else FLoadedStream := FileOrUrl;
  end;
  CreateTimers;
end;

Method for playing it, and retreiving length, maybe some error here?

procedure TBassPlayer.PlayStream;
begin
  FPaused := FALSE;
  case GetStreamType of
    btWMA: FLength := BASS_WMA_StreamGetLength(GetStreamHandle);
    else FLength := BASS_StreamGetLength(GetStreamHandle);
  end;
  FLengthSecs := Bass_ChannelBytes2Seconds(GetStreamHandle, FLength);
  UpdateStreamData;
  if FLength > 0 then begin
    if GetStreamType = btWMA then FBitrate := Round((BASS_WMA_StreamGetLength(GetStreamHandle) * 8) / FLength)
    else FBitrate := Round((Bass_StreamGetFilePosition(GetStreamHandle,2) * 8) / FLength);
  end
  else FBitrate := 0;
  FStreamData.Playing := TRUE;
  CreateTimers;
end;

And another method to set the position...

procedure TBassPlayer.SetPosition(Value: Int64);
begin
  if Value <> FPosition then begin
    if (not FDecodeOnly) then begin
      case GetStreamType of
        btWMA: Bass_WMA_ChannelSetPosition(GetStreamHandle, Value);
        else Bass_ChannelSetPosition(GetStreamHandle, Value);
      end;
      FPosition := Value;
    end;
  end;
end;

WingZero

Just to be sure, you says ErrorGetCode and BASS_ErrorGetCode, but did you try BASS_WMA_ErrorGetCode?

Ingolf

#10
AARGH! I sure hope so! I hope I'm not that stupid. Let's try that.

Damnit! You were right! BASS_WMA_ErrorGetCode returns 0, BASS_ErrorGetCode returns 24, so that's another error I'll have to look in to. Didn't know there was a WMA_ErrorGetCode too. sorry!

There is still my positioning problem, so maybe someone can take a look at my code to see if something is wrong.

Ian @ un4seen

I can't see where "GetStreamType" is defined, but you're sure that the program is successfully calling BASS_WMA_ChannelSetPosition? I suggest sticking a break-point on all the BASS calls, and tracing through the program, to be sure that the correct function versions are being called (and that the calls are successful).

BASSWMA 1.8 will be more integrated with BASS - almost all the WMA functions are gone, instead you use the standard BASS versions. You won't have to worry about calling the wrong function version then :)

Irrational86

Nice, i like BASSWMA 1.8 better and...when will it be released? ;D

Ian @ un4seen

BASS/WMA 1.8 are almost done (mostly just testing now), so it should be this month :)

Ingolf

Nice! I'll check it out further more, otherwise I'll wait for 1.8. Thanks!

GetStreamType is real simple, just returns the stream type (music, stream, wma, etc.) of the current stream. It returns WMA in this case.