Author Topic: BASSmix beta (mixing & resampling add-on)  (Read 125225 times)

Ian @ un4seen

  • Administrator
  • Posts: 20433
BASSmix beta (mixing & resampling add-on)
« on: 16 Oct '05 - 17:22 »
A fairly common question is how to mix and/or resample channels. To make that task simple, here's an add-on that'll do it...

   [see the BASS page]
« Last Edit: 30 Jul '07 - 15:07 by Ian @ un4seen »

Wolfgang.Wester

  • Guest
Re: BASSmix beta (mixing & resampling add-on)
« Reply #1 on: 18 Oct '05 - 07:39 »
@Ian,

looks very promisingly....
How about the performance ?

Cheers, Wolfgang

Sebastian Andersson

  • Posts: 372
Re: BASSmix beta (mixing & resampling add-on)
« Reply #2 on: 18 Oct '05 - 10:37 »
How about the performance ?

I think it's fast enough already, or I'm not sure what speed you expected it to process at.

Sebastian Andersson

  • Posts: 372
Re: BASSmix beta (mixing & resampling add-on)
« Reply #3 on: 18 Oct '05 - 11:06 »
I wrapped up a C example for BASSmix yesterday. It's based on "contest", and allows users to specify sample rate/channels and the files to mix.

     http://www.un4seen.com/filez/2/contest.c

Wolfgang Wester

  • Posts: 19
Re: BASSmix beta (mixing & resampling add-on)
« Reply #4 on: 18 Oct '05 - 13:40 »
Thanks for the example  :D

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: BASSmix beta (mixing & resampling add-on)
« Reply #5 on: 19 Oct '05 - 11:58 »
An update is now in the BASSmix ZIP, with a new downmixing option. There are also a couple of bug fixes.

radio42

  • Posts: 4576
Re: BASSmix beta (mixing & resampling add-on)
« Reply #6 on: 19 Oct '05 - 22:13 »
Nice work!!!

One thing:
What is the BASS_SPEAKER_xxx in the "BASS_Mixer_StreamAddChannel" good for.

The downmix stuff is clear, but you state, that for any multi-channel sources the respective chans are taken anyhow?!

So when and why to use the BASS_SPEAKER_xxx flags ?

THX

Soon in BASS .NET for C# as well ;-)

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: BASSmix beta (mixing & resampling add-on)
« Reply #7 on: 20 Oct '05 - 13:55 »
The SPEAKER flags come into play in exactly the same way as with normal playback channels. If you have a multi-channel mixer, you can place stereo/mono source channels on specific "speakers" in the mix.

The SPEAKER flags do not apply to multi-channel sources, again, just like with normal playback channels :) ... If you want, you can downmix a multi-channel source, then you can use the SPEAKER flags with it, ie. use the DOWNMIX flag together with the SPEAKER flag.

radio42

  • Posts: 4576
Re: BASSmix beta (mixing & resampling add-on)
« Reply #8 on: 20 Oct '05 - 20:03 »
I see,
so if I have simple stereo sources only
and
the output mixer channel is also only stereo
and
eg. the output mixer already was set up with SPEAKER flag in "BASS_Mixer_StreamCreate"

-> then it wouldn't make much sense to use it - right?!

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: BASSmix beta (mixing & resampling add-on)
« Reply #9 on: 21 Oct '05 - 16:52 »
I see,
so if I have simple stereo sources only
and
the output mixer channel is also only stereo
and
eg. the output mixer already was set up with SPEAKER flag in "BASS_Mixer_StreamCreate"

-> then it wouldn't make much sense to use it - right?!

Do you mean it wouldn't make much sense to use SPEAKER flags in the BASS_Mixer_StreamAddChannel calls? If so, yep - you could use BASS_SPEAKER_FRONT, but it wouldn't achieve anything :)

wmm

  • Posts: 3
Re: BASSmix beta (mixing & resampling add-on)
« Reply #10 on: 4 Nov '05 - 08:15 »
Any VB sample code to mix a few channels? For example I want to mix 3 Mp3 tracks and finally output the mixed one to a WAV. Any help will be appreciated.  8)

engineeer

  • Posts: 86
Re: BASSmix beta (mixing & resampling add-on)
« Reply #11 on: 4 Nov '05 - 11:16 »
  • BASS_MIXER_DOWNMIX definition missing in BASSmix.pas
  • It seems that small amount of data stays in buffer when remove source channel. If remove last source and add new source, part of previous source will be heard
  • Is it possible to add pause/play functions for mixer source? Channel functions don't work because mixer source is decoding channel
« Last Edit: 4 Nov '05 - 11:33 by engineeer »

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: BASSmix beta (mixing & resampling add-on)
« Reply #12 on: 4 Nov '05 - 13:50 »
Any VB sample code to mix a few channels? For example I want to mix 3 Mp3 tracks and finally output the mixed one to a WAV. Any help will be appreciated.  8)

If you take the writewav example as a starting point, you would change the "btnLoadFile_Click" stuff to something like this...

Code: [Select]
chan = BASS_Mixer_StreamCreate(44100, 2, BASS_STREAM_DECODE) ' 44100hz stereo 16-bit mixer
source1 = BASS_StreamCreateFile(BASSFALSE, FileName1, 0, 0, BASS_SAMPLE_FLOAT or BASS_STREAM_DECODE)
BASS_Mixer_StreamAddChannel(chan, source1, 0) ' plug source1 into mixer
source2 = BASS_StreamCreateFile(BASSFALSE, FileName2, 0, 0, BASS_SAMPLE_FLOAT or BASS_STREAM_DECODE)
BASS_Mixer_StreamAddChannel(chan, source2, 0) ' plug source2 into mixer
source3 = BASS_StreamCreateFile(BASSFALSE, FileName3, 0, 0, BASS_SAMPLE_FLOAT or BASS_STREAM_DECODE)
BASS_Mixer_StreamAddChannel(chan, source3, 0) ' plug source3 into mixer

BASS_MIXER_DOWNMIX definition missing in BASSmix.pas

That's strange. I can see it in there :)

Code: [Select]
  BASS_MIXER_DOWNMIX = $400000; // downmix to stereo (or mono if mixer is mono) 
It seems that small amount of data stays in buffer when remove source channel. If remove last source and add new source, part of previous source will be heard

I guess that's when playing the mixer output? It's because of the playback buffer - there'll be some data from the old channel still in the buffer. You shouldn't hear an overlap though, as the new channel will be equally delayed.

Reducing the buffer length (BASS_CONFIG_BUFFER) will improve things (reduce the latency).

Is it possible to add pause/play functions for mixer source? Channel functions don't work because mixer source is decoding channel

Removing/adding (BASS_Mixer_ChannelRemove/BASS_Mixer_StreamAddChannel) the source channels should have the same effect as pausing/resuming. When the source is re-added, it'll be at the position it was when it was removed.

wmm

  • Posts: 3
Re: BASSmix beta (mixing & resampling add-on)
« Reply #13 on: 4 Nov '05 - 15:41 »
Thanks Ian. I am planning to get a shareware license for my product however I need to get some of my issues resolved, one of which I have posted in another thread. Mainly I intend to add a Mixing capability to the applicattion. For now I have done this using 3 handles and using the stereo mix as the selected source. However this is not a true solution.

so what i am looking for is like this -
load 3 files on 3 channels (handles) and show the osc graph.
copy and paste track portions of the tracks to a new track with fade in fade out feature.
save new track as wav file.

Can this be accomplished? Please suggest.

engineeer

  • Posts: 86
Re: BASSmix beta (mixing & resampling add-on)
« Reply #14 on: 4 Nov '05 - 22:55 »
I'm getting access violation in bassmix.dll when source channel ends.
Let me know if you need additional info...

robertpnl

  • Posts: 41
Re: BASSmix beta (mixing & resampling add-on)
« Reply #15 on: 5 Nov '05 - 13:47 »
I'm getting access violation in bassmix.dll when source channel ends.
Let me know if you need additional info...

Here also. Only with WAV files. By ending a MP3 file, i didn't get a access violation in bassmix.dll.

Here the code that i taken from the bassmix.chm:

Code: [Select]
// Bass Init
if (!Bass.BASS_Init(-1, 44100, 0, 0, null))
  throw new ApplicationException("Error BAS Init.");

// this will be the final mixer output stream being played
 int mixerStream = BassMix.BASS_Mixer_StreamCreate(44100, 2, 0 );
// now we need some channels to plug them in...
int streamA = Bass.BASS_StreamCreateFile,@"C:\WINDOWS\Media\ding.wav", 0, 0, BASSStream.BASS_STREAM_DECODE | BASSStream.BASS_SAMPLE_FLOAT);
int streamB = Bass.BASS_StreamCreateFile(@"testfile.mp3", 0, 0, BASSStream.BASS_STREAM_DECODE | BASSStream.BASS_SAMPLE_FLOAT);
// finally we plug them into the mixer (just to be sure, we use the downmix option to stereo)
bool okA = BassMix.BASS_Mixer_StreamAddChannel(mixerStream, streamA, (int)BASSStream.BASS_MIXER_DOWNMIX);
//bool okB = BassMix.BASS_Mixer_StreamAddChannel(mixerStream, streamB, (int)BASSStream.BASS_MIXER_DOWNMIX);
// and play it...
Bass.BASS_ChannelPlay(mixerStream, false);
Console.ReadLine();

And when stream A (.wav) is ending the file, a access violation will be viewed.

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: BASSmix beta (mixing & resampling add-on)
« Reply #16 on: 5 Nov '05 - 17:23 »
Oops! That crash should be sorted now (update in the BASSmix ZIP).


so what i am looking for is like this -
load 3 files on 3 channels (handles) and show the osc graph.
copy and paste track portions of the tracks to a new track with fade in fade out feature.
save new track as wav file.

Can this be accomplished? Please suggest.

Yes, you could do that with BASSmix. You can position the source channels (BASS_ChannelSetPosition) to their start points before you start processing (BASS_ChannelGetData). BASSmix doesn't have automated attributes, ie. you can't tell it to fade channels in/out (you can use BASS_ChannelSlideAttributes but that'll only be any good during playback). But you can choose how much data to process, so during fades, you could do small amounts, adjust the channel volumes (BASS_ChannelSetAttributes), and repeat.

engineeer

  • Posts: 86
Re: BASSmix beta (mixing & resampling add-on)
« Reply #17 on: 6 Nov '05 - 13:45 »
Ian, can you implement autofree of source channels as option?
If not, please suggest efficient way how to accomplish this.

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: BASSmix beta (mixing & resampling add-on)
« Reply #18 on: 7 Nov '05 - 17:39 »
Ok, I've added support for the BASS_STREAM_AUTOFREE flag in the BASS_Mixer_StreamAddChannel function (update in the ZIP). I've not tested it much yet, so let me know if you have any problems with it.

3delite

  • Posts: 907
Re: BASSmix beta (mixing & resampling add-on)
« Reply #19 on: 7 Nov '05 - 18:29 »
If I would use a mixer stream for ASIO output what would be the simplest way to do this?  ::)

3delite

  • Posts: 907
Re: BASSmix beta (mixing & resampling add-on)
« Reply #20 on: 8 Nov '05 - 13:50 »
 
I got this far:

Code: [Select]
var
  MainMixerStream: Cardinal = 0;
  SilentChannel: Cardinal = 0;
  ASIOInfo: BASS_ASIO_INFO;

procedure StreamSilentChannel(Channel: DWORD; Buffer: Pointer; Length: Cardinal; User: DWORD); stdcall;
begin
    ZeroMemory(Buffer, Length);
end;

procedure asioproc(Input: Boolean; Channel: DWORD; Buffer: Pointer; Length: Cardinal; User: DWORD); stdcall
begin
BASS_ChannelGetData(User, Buffer, Length);
end;

procedure ASIOPlay;
var
  i: Integer;
  ChanInfo: BASS_CHANNELINFO;
  ASIOChanInfo: BASS_ASIO_CHANNELINFO;
  tmpStream: TBassStreamItem;
begin
    BASS_ASIO_Stop;
    BASS_ChannelGetInfo(MainMixerStream, ChanInfo);
    BASS_ASIO_ChannelEnable(False, 0, @asioproc, MainMixerStream);
    for i := 0 to ChanInfo.chans - 1
        do BASS_ASIO_ChannelJoin(False, i, 0);
    BASS_ASIO_ChannelSetFormat(false, 0, BASS_ASIO_FORMAT_Float);
    BASS_ASIO_ChannelSetRate(False, 0, ChanInfo.freq);
    // try to set the device rate too (saves resampling)
    BASS_ASIO_SetRate(ChanInfo.freq);
    if NOT BASS_ASIO_Start(0) then begin
        SettingsWindow.EditStatus.Text := 'Error: Can''t start ASIO output.';
        Showmessage('Error: Can''t start ASIO output.')
    end;
end;

procedure Init;
begin
        //* MainMixer
        MainMixerStream := BASS_Mixer_StreamCreate(freq, 2, BASS_STREAM_DECODE);
        SilentChannel := BASS_StreamCreate(44100, 2, BASS_STREAM_DECODE, @StreamSilentChannel, 0);
        BASS_Mixer_StreamAddChannel(MainMixerStream, SilentChannel, BASS_STREAM_DECODE);
        //* ASIO
        BASS_ASIO_Free;
        if SettingsWindow.CheckBoxASIO.Checked then begin
            if NOT BASS_ASIO_Init(0)
                then Showmessage('Error: Can''t initialize ASIO device.');
            BASS_ASIO_GetInfo(ASIOInfo);
            Log(ASIOInfo.Name, True);
            Settingswindow.EditStatus.Text := ASIOInfo.Name;
            Settingswindow.EditStatus.Hint := Settingswindow.EditStatus.Text;
            ASIOPlay;
        end;

But I only get noise when nothing is playing, and hear nothing when I plug a channel stream into the mixer channel.

Code: [Select]
        Result := BASS_Mixer_StreamAddChannel(MainMixerStream, Channel, 0)

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: BASSmix beta (mixing & resampling add-on)
« Reply #21 on: 8 Nov '05 - 14:39 »
When there are no channels plugged into the mixer, it will return no data, so you'll need to fill the ASIO buffer with 0s (silence)...

Code: [Select]
void CALLBACK AsioProc(BOOL input, DWORD channel, void *buffer, DWORD length, DWORD user)
{
DWORD c=BASS_ChannelGetData(user,buffer,length);
if (c<length) ZeroMemory(((BYTE*)buffer)+c,length-c);
}

Also, the mixer and ASIO channels should have the same sample format, eg. if the ASIO channel is floating-point, the mixer should be too :)

big_gun

  • Posts: 352
Re: BASSmix beta (mixing & resampling add-on)
« Reply #22 on: 8 Nov '05 - 16:35 »
I'm trying to combine one or more mp3s into one mp3, back to back.

I took the contest.c example and tried to port it into VB.NET I got pretty far. I'm passing in "44100 2 <file1> <file2>"

Depending on the BASS_Init device, and the decode flags, I'm getting it to show the times, and run through the first file, then it hangs. The MP3 it created is the right size, but no sound.

Otherwise it gives me this error:

Code: [Select]
mixing/streaming files...
c:\My Music\Black Eyed Peas, The - My Humps.mp3
c:\My Music\Chris Brown - Run It!.mp3

Error: The encoder died!
All is OK

Press Enter to close this application

Here's the source code:

Code: [Select]

    Sub Main()

        Dim argv() As String = System.Environment.GetCommandLineArgs

        ' check that BASS 2.2 was loaded
        If Bass.BASS_GetVersion <> Utils.MakeLong(2, 2) Then
            printf("BASS version 2.2 was not loaded\n")
            Return
        End If

        If argv.Length < 4 Then
            printf("usage: %s <freq> <chans> <file1> <file2> ...\n")

            printf("\nPress Enter to close this application\n")
            Console.Read()

            Return
        End If

        ' not playing anything, so don't need an update thread
        Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0)

        If Not (Bass.BASS_Init(-1, 44100, 0, 0, Nothing)) Then
            printf("error: can't open output device\n")
            printf("\nPress Enter to close this application\n")
            Console.Read()
            Return
        End If

        If Not Bass.BASS_Start() Then
            printf("error: can't start output\n")
            printf("\nPress Enter to close this application\n")
            Console.Read()
            Return
        End If

        Chan = AddOn.Mix.BassMix.BASS_Mixer_StreamCreate(atol(argv(1)), atol(argv(2)), 0) 'BASSStream.BASS_STREAM_DECODE)
        If Chan = 0 Then
            printf("error: can't create mixer output\n")
            printf("\nPress Enter to close this application\n")
            Console.Read()
            Bass.BASS_Free()
            Return
        End If

        printf("mixing/streaming files...\n")

        For A = 3 To argv.Length - 1
            ' insert channels into mixer
            If AddOn.Mix.BassMix.BASS_Mixer_StreamAddChannel(Chan, Bass.BASS_StreamCreateFile(argv(A), 0, 0, BASSStream.BASS_STREAM_DECODE), 0) Then 'BASSStream.BASS_STREAM_DECODE) Then
                printf(argv(A) + "\n")
            End If
        Next
        printf("\n")

        'Encoder = EncodeType.MP3
        EncodeCommands(EncodeType.OGG) = "oggenc.exe -b 128 -o """ + OutputFile + """ -"
        EncodeCommands(EncodeType.MP3) = "lame.exe -b 128 - """ + OutputFile + """"


        EncHandle = AddOn.Enc.BassEnc.BASS_Encode_Start(Chan, EncodeCommands(1), AddOn.Enc.BASSEncode.BASS_ENCODE_FP_16BIT, Nothing, 0)
        If EncHandle = 0 Then
            printf(BASS_GetErrorDescription(Bass.BASS_ErrorGetCode) + "\n")
            printf("\nPress Enter to close this application\n")
            Console.Read()
            Bass.BASS_Free()
        End If

        If Not Bass.BASS_ChannelPlay(Chan, True) Then
            printf("Cannot play... " + BASS_GetErrorDescription(Bass.BASS_ErrorGetCode) + "\n")
            printf("\nPress Enter to close this application\n")
            Console.Read()
            Bass.BASS_Free()
            Return
        End If

        Do While Bass.BASS_ChannelIsActive(Chan) = Un4seen.Bass.BASSActive.BASS_ACTIVE_PLAYING
            ' display some stuff and wait a bit
            level = Bass.BASS_ChannelGetLevel(Chan)
            pos = Bass.BASS_ChannelGetPosition(Chan)
            sTime = Bass.BASS_ChannelBytes2Seconds(Chan, pos)

            RetVal = Bass.BASS_ChannelGetData(Chan, MusicTemp(0), 20000)

            If AddOn.Enc.BassEnc.BASS_Encode_IsActive(EncHandle) <> BASSActive.BASS_ACTIVE_PLAYING Then
                printf("Error: The encoder died!\n")
                printf(BASS_GetErrorDescription(Bass.BASS_ErrorGetCode) + "\n")
                Exit Do
            End If

            If tmp <> Utils.FixTimespan(sTime, "MMSS") Then
                tmp = Utils.FixTimespan(sTime, "MMSS")

                printf("pos " + tmp + "\n")
            End If

            System.Threading.Thread.CurrentThread.Sleep(1)
        Loop
        Bass.BASS_ChannelStop(Chan)

        AddOn.Enc.BassEnc.BASS_Encode_Stop(Chan)


        Bass.BASS_StreamFree(Chan)

        Bass.BASS_Stop()
        Bass.BASS_Free()

        printf("\nPress Enter to close this application\n")
        Console.Read()

        Return
    End Sub

Thanks for your help!

Rick

3delite

  • Posts: 907
Re: BASSmix beta (mixing & resampling add-on)
« Reply #23 on: 8 Nov '05 - 17:05 »
When there are no channels plugged into the mixer, it will return no data, so you'll need to fill the ASIO buffer with 0s (silence)...

Code: [Select]
void CALLBACK AsioProc(BOOL input, DWORD channel, void *buffer, DWORD length, DWORD user)
{
DWORD c=BASS_ChannelGetData(user,buffer,length);
if (c<length) ZeroMemory(((BYTE*)buffer)+c,length-c);
}
Aaaaah I don't understand that!!! :) This seems working:
 
Code: [Select]
procedure asioproc(Input: Boolean; Channel: DWORD; Buffer: Pointer; Length: Cardinal; User: DWORD); stdcall
var
  GotData: Cardinal;
begin
GotData := BASS_ChannelGetData(User, Buffer, Length);
    if GotData < Length
        then ZeroMemory(Pointer(Cardinal(Buffer) + GotData), Length - GotData);
end;

That seems like solved the noise issue (now it's silent when there is nothin playing) but still no sound when I plug a channel into the mixer stream. I really don't have any ideas!  :(

Also, the mixer and ASIO channels should have the same sample format, eg. if the ASIO channel is floating-point, the mixer should be too :)

Changed that but still no sound! :'(
The problem is that I don't understand the logic.
Is the following good for a custom stream (STREAMPROC)!?
 
Code: [Select]
procedure StreamSilentChannel(Channel: DWORD; Buffer: Pointer; Length: Cardinal; User: DWORD); stdcall;
begin
    ZeroMemory(Buffer, Length);
end;
I want a custom stream that is silent. So that the ASIO could play all the time (the silence).
It seems that GotData is always 0, but why!?
 
« Last Edit: 8 Nov '05 - 17:15 by 3delite »

3delite

  • Posts: 907
Re: BASSmix beta (mixing & resampling add-on)
« Reply #24 on: 8 Nov '05 - 17:25 »
 
Ah, Ian! You didn't notice it!? The STREAMPROC was wrong, it wasn't returning the copied bytes, the correct one is:
 
Code: [Select]
function StreamSilentChannel(Channel: DWORD; Buffer: Pointer; Length: Cardinal; User: DWORD): DWORD; stdcall;
begin
    ZeroMemory(Buffer, Length);
    Result := Length;
end;

But there is still no sound. BTW I can see the channel is being streamed as the position bar is moving, but no sound is output. :-\

If I change the ASIOPROC to ChannelGetData() from a simple stream channel there is sound, so the problem must be with the mixer or custom channel.
Still no ideas...

But I am still angry about ChannelGetLevel() stealing data from ChannelGetData() >:(
There should be differences with that two functions! So I can always see, what's happening with the particular channel. ::)
 
« Last Edit: 8 Nov '05 - 19:57 by 3delite »