Clone "mixed" stream to another output device ?

Started by Couin,

Couin

Hi Ian,

Thanks, I got the same result with simpler solution.

About ASIO output, I so added a mixer which receive mic and the other mixer. Now I have audio files and mic played by ASIO output  :)

Here is the code, perhapps is there a better way ?

Private Sub Form_Load()
    'change and set the current path
    'so it won't ever tell you, that "bass.dll" isn't found
    ChDrive App.Path
    ChDir App.Path

    'check if "bass.dll" is exists
    If (Not FileExists(RPP(App.Path) & "bass.dll")) Then
        Call MsgBox("BASS.DLL does not exists", vbCritical, "BASS.DLL")
        End
    End If

    ' check the correct BASS was loaded
    If (HiWord(BASS_GetVersion) <> BASSVERSION) Then
        Call MsgBox("An incorrect version of BASS.DLL was loaded", vbCritical)
        End
    End If

    'check if "bassasio.dll" is exists
    If (Not FileExists(RPP(App.Path) & "bassasio.dll")) Then
        Call MsgBox("BASSASIO.DLL does not exists", vbCritical, "BASSASIO.DLL")
        End
    End If

    'let the user choose the output devices
    With frmDevice
        .SelectDevice 1
        .Show vbModal, Me
        outdev(0) = .device
    End With

    'not playing anything via BASS, so don't need an update thread
    Call BASS_SetConfig(BASS_CONFIG_UPDATEPERIOD, 0)

    'initialize BASS - "no sound" device
    Call BASS_Init(0, 48000, 0, 0, 0)

    'initialize ASIO devices
    If (BASS_ASIO_Init(outdev(0), 0) = 0) Then
        Call Error_("Can't initialize device 1")
        Unload Me
    End If

    Call BASS_ASIO_SetDevice(outdev(0)) 'set the ASIO device to work with
    Call BASS_ASIO_Stop   'stop the device
    Call BASS_ASIO_ChannelReset(0, -1, BASS_ASIO_RESET_ENABLE Or BASS_ASIO_RESET_JOIN) 'disable & unjoin all output channels

    ' Mixer for audio files
    Call BASS_StreamFree(mixer)
    mixer = BASS_Mixer_StreamCreate(BASS_ASIO_GetRate(), 2, BASS_SAMPLE_FLOAT Or BASS_STREAM_DECODE)
   
    SplitOutput(0) = BASS_Split_StreamCreate(mixer, BASS_STREAM_DECODE, ByVal 0)
    Call BASS_ChannelSetAttribute(SplitOutput(0), BASS_ATTRIB_BUFFER, 0)
    Call BASS_ChannelStart(SplitOutput(0))
   
    'Mixer for ASIO output (receive mic splitted stream and audio files mixer output)
    Call BASS_StreamFree(mixermic)
    mixermic = BASS_Mixer_StreamCreate(BASS_ASIO_GetRate(), 2, BASS_SAMPLE_FLOAT Or BASS_STREAM_DECODE)
    Call BASS_Mixer_StreamAddChannel(mixermic, SplitOutput(0), BASS_MIXER_CHAN_BUFFER)
   
    Call BASS_ASIO_ChannelEnableBASS(False, 0, mixermic, True)
       
    ' Mic stream
    micchan = BASS_StreamCreate(BASS_ASIO_GetRate(), 2, BASS_SAMPLE_FLOAT Or BASS_STREAM_DECODE, STREAMPROC_PUSH, 0)
    Call BASS_ASIO_ChannelEnableBASS(BASSTRUE, 0, micchan, BASSTRUE)
       
    SplitMic(0) = BASS_Split_StreamCreate(micchan, BASS_STREAM_DECODE, ByVal 0)
    Call BASS_ChannelSetAttribute(SplitMic(0), BASS_ATTRIB_BUFFER, 0)
    Call BASS_ChannelSlideAttribute(SplitMic(0), BASS_ATTRIB_VOL, 0, 10)
    Call BASS_ChannelStart(SplitMic(0))
   
    Call BASS_Mixer_StreamAddChannel(mixermic, SplitMic(0), BASS_MIXER_CHAN_BUFFER)
   
    Call BASS_ASIO_Start(0, 0)
   
    Dim dev ' NON ASIO device number
    dev = 5
    Call BASS_Init(dev, 44100, 0, 0, 0)
    Call BASS_SetDevice(dev)
    SplitOutput(1) = BASS_Split_StreamCreate(mixer, 0, ByVal 0)
    Call BASS_ChannelSetAttribute(SplitOutput(1), BASS_ATTRIB_BUFFER, 0)
    Call BASS_ChannelStart(SplitOutput(1))
    SplitMic(1) = BASS_Split_StreamCreate(micchan, 0, ByVal 0)
    Call BASS_ChannelSetAttribute(SplitMic(1), BASS_ATTRIB_BUFFER, 0)
    Call BASS_ChannelSlideAttribute(SplitMic(1), BASS_ATTRIB_VOL, 0, 10)
    Call BASS_ChannelStart(SplitMic(1))   
End Sub
Of course, the audio files plays once loaded (from a Commond Dialog), like in the "Multi" project.

Minor question: Is a mixer adding latency ?

About mic volume, I added a push button to set volume to volume setting when push button and 0 when release it. It sometimes make an audio "click", so I changed for:
Call BASS_ChannelSlideAttribute(SplitMic(Index), BASS_ATTRIB_VOL, Slider2(Index).value / 100, 100) to get a smooth volume transistion (so no more "click").

If code looks OK, I just have to implent ii (with also condition to switch between "ASIO + NON ASIO" and "NON ASIO + NON ASIO" devices), so again some neurons will die  ;D

Ian @ un4seen

Quote from: CouinMinor question: Is a mixer adding latency ?

No. When BASS_STREAM_DECODE is set on it, the mixer won't have any buffering, so no extra latency. If the mixer has to resample a source (due to differing sample rates) then there will actually be a small buffer for that, but nothing very significant.

Quote from: CouinAbout mic volume, I added a push button to set volume to volume setting when push button and 0 when release it. It sometimes make an audio "click", so I changed for:
Call BASS_ChannelSlideAttribute(SplitMic(Index), BASS_ATTRIB_VOL, Slider2(Index).value / 100, 100) to get a smooth volume transistion (so no more "click").

The mixer should automatically ramp its sources' BASS_ATTRIB_VOL changes to avoid clicks, so it shouldn't be necessary to use BASS_ChannelSlideAttribute for that purpose. Are you sure it is?

This doesn't apply to BASS_ATTRIB_VOLDSP changes. If you happen to want to ramp that then using the BASS_BFX_VOLUME effect (which includes ramping) instead will give a smoother result.

Couin

Hi Ian,
I was getting "clicks" with BASS_ATTRIB_VOLDSP  on split DECODE channels of MIC Input. But with Slide it's OK :)

I'm now trying to implent the test example in JP (the target app), but of course, I get problems (not working AHAH). So I'm trying to build mixer etc one by one and I get big latency to measure playback posiition with BASS_ChannelGetPosition(chan(index), BASS_POS_BYTE) .

Also, to send a mixer output, just have to BASS_ChannelStart(mixer) ? Because I get no playback (and not position measurement) when I play a soruce.

I probably miss something :)

Thanks

Ian @ un4seen

Quote from: CouinI was getting "clicks" with BASS_ATTRIB_VOLDSP  on split DECODE channels of MIC Input. But with Slide it's OK :)

OK, so you're calling BASS_ChannelSlideAttribute with BASS_ATTRIB_VOLDSP rather than BASS_ATTRIB_VOL? Are you plugging the splitter into a mixer? If so, you could use BASS_ATTRIB_VOL instead, so that the mixer automatically ramps changes to avoid clicks.

Quote from: CouinAlso, to send a mixer output, just have to BASS_ChannelStart(mixer) ? Because I get no playback (and not position measurement) when I play a soruce.

You would use BASS_ChannelStart with normal BASS output but not ASIO. Basically, if a stream has the BASS_STREAM_DECODE flag set then it can't be played with BASS_ChannelStart/Play. If the call is having no effect then perhaps you used it on your ASIO mixer? Check the return value to confirm whether it was successful (and error code if not).

Couin

Hi Ian,

By doing tons of tests and modifications, I finish to no longer know what I did or didn't, my head is burning :(

I'm re-taking from the beginning the adding mixers etc etc to the project.

I would build a "common" structure with 4 mixers:
- 1 for audio files (MixerSources)
- 1 for mic input (MixerMic)
- 1 for main output device (MixerMain)
- 1 for aux output device (MixerAux)

About aux output device, it will be for example, to send to Virtual Cable, so NON ASIO.

About Mic Input and Main output device, they could be NON ASIO or ASIO devices, so I should only change code before MixerMic and after MixerMain, depending of which device type user choose.

For the moment, I use NON ASIO.

Refering to the nice joined schematic, after some hours of code work, I get now good results: I can set the output volume for each devices (SplitOutDev), and mic volume sent to each mixer before output devices (SplitMic).

I would make the ASIO code part tomorow but now, the duck goes to bed now (AM 5:30, French timezone hahah) !

Ian @ un4seen

Yes, if ASIO would be optional then I would suggest getting everything else working well first, and only add the ASIO stuff (if still needed) after that.

Regarding your latest schematic, are you sure the "MixerMic" is needed, as it doesn't appear to be mixing anything? Couldn't you create the "SplitMic" splitters directly on the recording?

Couin

I agree, I will see with optional ASIO input, and if possible , I will replace MixerMic by a splitter :)

Couin

Hi :)

A minor (because I get it only on one XP virtual machine) question:
I measure the level of SplitOutDev (0 or 1) with BASS_ChannelGetLevel and I noticed that it randomly miss measure and returns level at 0 resulting to blinking (off) VU-meters. I get the same with BASS_ChannelGetLevelEx.

If I measure SplitSources(0 or 1) level, no problem.

Different buffer 0 flags are there, here is the code of mixers assembly:

    MixerSources = BASS_Mixer_StreamCreate(44100, 2, BASS_SAMPLE_FLOAT Or BASS_STREAM_DECODE)
    Call BASS_ChannelSetAttribute(MixerSources, BASS_ATTRIB_BUFFER, 0)

    MixerMic = BASS_Mixer_StreamCreate(44100, 2, BASS_SAMPLE_FLOAT Or BASS_STREAM_DECODE)
    Call BASS_ChannelSetAttribute(MixerMic, BASS_ATTRIB_BUFFER, 0)
   
    For nSplit = 0 To 1
        SplitSources(nSplit) = BASS_Split_StreamCreate(MixerSources, BASS_STREAM_DECODE, ByVal 0)
        SplitMic(nSplit) = BASS_Split_StreamCreate(MixerMic, BASS_STREAM_DECODE, ByVal 0)
    Next nSplit
   
    MixerMain = BASS_Mixer_StreamCreate(44100, 2, BASS_SAMPLE_FLOAT Or BASS_STREAM_DECODE)
    Call BASS_ChannelSetAttribute(MixerMain, BASS_ATTRIB_BUFFER, 0)
   
    MixerAux = BASS_Mixer_StreamCreate(44100, 2, BASS_SAMPLE_FLOAT Or BASS_STREAM_DECODE)
    Call BASS_ChannelSetAttribute(MixerAux, BASS_ATTRIB_BUFFER, 0)
       
    Call BASS_Mixer_StreamAddChannel(MixerMain, SplitSources(0), BASS_MIXER_CHAN_BUFFER)
    Call BASS_Mixer_StreamAddChannel(MixerAux, SplitSources(1), BASS_MIXER_CHAN_BUFFER)
    Call BASS_Mixer_StreamAddChannel(MixerMain, SplitMic(0), BASS_MIXER_CHAN_BUFFER)
    Call BASS_Mixer_StreamAddChannel(MixerAux, SplitMic(1), BASS_MIXER_CHAN_BUFFER)
       
    Call BASS_SetDevice(OutDev(0))
    SplitOutDev(0) = BASS_Split_StreamCreate(MixerMain, 0, ByVal 0)
    Call BASS_ChannelSetAttribute(SplitOutDev(0), BASS_ATTRIB_BUFFER, 0)
    Call BASS_ChannelStart(SplitOutDev(0))
   
    Call BASS_SetDevice(OutDev(1))
    SplitOutDev(1) = BASS_Split_StreamCreate(MixerAux, 0, ByVal 0)
    Call BASS_ChannelSetAttribute(SplitOutDev(1), BASS_ATTRIB_BUFFER, 0)
    Call BASS_ChannelStart(SplitOutDev(1))

Is there something I missed ?

Ian @ un4seen

That code looks fine, although you could remove the BASS_ATTRIB_BUFFER settings on the streams with BASS_STREAM_DECODE because they have no effect (no playback buffers involved). Does the stream still sound fine (eg. no breaks) when BASS_ChannelGetLevel returns 0 on it? Also, are you customising the BASS_CONFIG_DEV_PERIOD/BASS_CONFIG_DEV_BUFFER/BASS_CONFIG_BUFFER settings or using the defaults?

When you get the level of SplitSources, I guess you use BASS_Mixer_ChannelGetLevel rather than BASS_ChannelGetLevel?

Couin

I tried with both , no problem with measurement between MixerSources and MixerMain (excepted that with BASS_ChannelGetLevel the audio plays too fast).

Measuring MixerMain output receving zeros but sound still ok (no dropouts).

Ok for removing buffer on DECODE, (but it does not change the zeros problem).

Ian @ un4seen

Quote from: CouinI tried with both , no problem with measurement between MixerSources and MixerMain (excepted that with BASS_ChannelGetLevel the audio plays too fast).

Yes, you should only use BASS_Mixer_ChannelGetLevel on mixer sources, because the data taken by BASS_ChannelGetLevel wouldn't be seen by the mixer (causing skipping/speedy playback).

Quote from: CouinMeasuring MixerMain output receving zeros but sound still ok (no dropouts).

Do you mean BASS_ChannelGetLevel on SplitOutDev? To perhaps narrow it down, does it still happen if you don't set BASS_ATTRIB_BUFFER to 0 on SplitOutDev?

Couin

Hi Ian

Removing buffer attribute resolves the "missing measures" but makes getposition jerky (resulting to a remaining time slow refresh). Plus, it add delay bewteen hitting play and sound.

Couin

Hi :)

I'm modifying ouput device selection method so now, changing device directly apply, without reloading audio files:
Call BASS_StreamFree(SplitOutDev(outp)) 'where outp is 0 or 1, related with Main or Aux outputs of the schematic here https://www.un4seen.com/forum/?topic=20403.msg143048#msg143048
Changing the device number et recreate the SplitOutDev (split) stream.

Works OK, but just a minor question (for a rare situation):
If Aux is firstly set on "None" device (so 0), if I played some jingle, when I change Aux for an output device, I get the end part of last playback.

I tried to add some BASS_Split_StreamReset calls , for SplitOutDev, MixerMain or MixerAux, but nothing change.
I added BASS_CONFIG_SPLIT_BUFFER, if I set to 0, I get no more part of last playback on device change, but playback is to fast and crappy. If I set to a value like 100, the playback speed is ok but I get a small part of previous playback.

Is there a way to clear buffer to prevent this ?

Thanks :D



Ian @ un4seen

Quote from: CouinRemoving buffer attribute resolves the "missing measures" but makes getposition jerky (resulting to a remaining time slow refresh). Plus, it add delay bewteen hitting play and sound.

OK. Here's a modified version of the CONTEST.C example for you to try for comparison, adding a BASS_ATTRIB_BUFFER=0 option and a BASS_DATA_AVAILABLE display:

   www.un4seen.com/stuff/contest-nobuf.exe

Please try that with and without the "-n" option (BASS_ATTRIB_BUFFER=0), and see whether the level display is working and what "data" values (BASS_DATA_AVAILABLE) are shown in each case. If it's working fine even with "-n" then you can also try monitoring the BASS_DATA_AVAILABLE values (with BASS_ChannelGetData) in your app to see if they're different.

Quote from: CouinI'm modifying ouput device selection method so now, changing device directly apply, without reloading audio files:
Call BASS_StreamFree(SplitOutDev(outp)) 'where outp is 0 or 1, related with Main or Aux outputs of the schematic here https://www.un4seen.com/forum/?topic=20403.msg143048#msg143048
Changing the device number et recreate the SplitOutDev (split) stream.

Works OK, but just a minor question (for a rare situation):
If Aux is firstly set on "None" device (so 0), if I played some jingle, when I change Aux for an output device, I get the end part of last playback.

A new splitter shouldn't play old data from its source, so it seems like the old sound may actually be in new data from the source. How much old sound are you getting? And is this happening on the same WinXP VM and/or on other systems? Does adding the BASS_MIXER_NONSTOP flag to MixerAux make any difference?

Couin

Hi Ian :)

BASS_MIXER_NONSTOP flag seems resolve the problem :)
(It's not on the XP VM of the level measurement problem, the re-playing was on a non-VM W10, which I use for main developpment).

About contest exe, I will test this afternoon at work (where is the XP VM on which I get some missing level measures), it's my last day before summer hollydays.

Couin

Hi Ian,

I tested the exe with and without -n flag, with a 10 seconds sine of 1 kHz @ max amplitude.

With -n , the VU-meters doesn't fall down. Data value runs around 20000, but sometimes with a near from 0 (too fast to read exactly), no sound problem.

Without -n , VU-meters still OK, Data around 160000 , and I did not saw 0 values.

Ian @ un4seen

Is that on the same system that you're having the BASS_ChannelGetLevel=0 problem with your app? If so, strange that it isn't happening with the modified example. You could try monitoring the BASS_DATA_AVAILABLE value in your app for comparison.

avail = BASS_ChannelGetData(handle, 0, BASS_DATA_AVAILABLE)

Also, if you're changing any config settings via BASS_SetConfig, try removing that to use the defaults (which is what the example does).

Couin

Yes, I tested your exe on the samed XP VM which makes some missing level measures.
But as I previoulsy wrote, I get missing messures on splitted output of second mixer (Main or Aux), but not if I measure between primary and secondary mixer ( so SplitSources ).

I took the pc where the VM is hosted, for hollydays :P
So I will be able to do tests on it (but not today and friday).

Couin

Hi :)

Working on ASIO output with a soundcard that has ASIO driver (Rane SL3) so now I understand better, about channels (as well as this soundcard has 3 Stereo outputsso GetInfo returns me "6").

I can setup on which pair of channels to send the splitted stream ( SplitOutDev(0) ), but if I want to change of channel pair, I must BASS_ASIO_Free and BASS_ASIO_Init, BASS_Split_StreamCreate, BASS_ASIO_ChannelEnableBASS etc and it takes a delay to do all these steps.

It's not a big problem, but is there a best way to change channels where to send stream, without free and init the device ?

Thanks :)

Ian @ un4seen

You don't actually need to call BASS_ASIO_Free and BASS_ASIO_Init to change the enabled ASIO channels. BASS_ASIO_Stop and BASS_ASIO_Start will suffice, like this:

BASS_ASIO_Stop(); // stop ASIO device
BASS_ASIO_ChannelEnable(false, oldoutput, 0, 0); // disable old channels
BASS_ASIO_ChannelEnableBASS(false, newoutput, handle, true); // enable new channels
BASS_ASIO_Start(0, 0); // resume ASIO device

If there are no other ASIO channels being used then you could use BASS_ASIO_ChannelReset instead of BASS_ASIO_ChannelEnable to disable the old channels, which has the advantage of not needing to know the "oldoutput" value.

BASS_ASIO_ChannelReset(false, -1, BASS_ASIO_RESET_ENABLE); // disable all output channels