Author Topic: Combining multiple files to one & stream  (Read 270 times)

Fabacon

  • Posts: 3
Combining multiple files to one & stream
« on: 17 Aug '17 - 16:46 »
First of all I am a complete newbie to BASS and not a native English speaker/writer. So I hope my question will be clear and that I am not opening unclosed doors here.  I would be very gratefull if anyone is willing to enlighten me with the answers I am looking for.

In the past I worked with Adobe Audition and batch recordings in combination with Macro Express. In this way I managed to automatically place short audio files on top of two other tracks. But it took a whole lot of finetuning and wasn't precise.

Now I learned to program in C# and I have a good hope BASS will be suitable to do what I wish. I will explain this:

I want to take an audio file of 30 minutes, place another one 'on top of that' - they both begin at 0 seconds and end at 30 minutes. Then on top of that I want to place 3 sets of a maximum of 15 small audio files. I want each set to start at a fixed time (5 minutes, 15 minutes and 25 minutes) and these small audio files with a variant interval, depending on their amount. Well, the calculating of this is not really the issue.

So what I would like to ask: is is possible with BASS to produce an audiofile that consists of multuple layers combined to one? Is there a limit, possibly to the load it may have on the cpu of memory? Can this output be streamed over the web?

Again, I realize that to you guys that are playing with audio and BASS this may sound as a silly issue, but for me it would really mean a lot to get some answers and/or example code so that I can start building.

Thanks in advance for your help!

Ian @ un4seen

  • Administrator
  • Posts: 20393
Re: Combining multiple files to one & stream
« Reply #1 on: 18 Aug '17 - 16:44 »
That sounds like it should be possible. You would need the BASSmix add-on for the mixing, and optionally the BASSenc add-on for the file writing. The basic steps would be to create a mixer, create decoders for the files that you want to mix, and plug them into the mixer at the wanted start times. I'm not a .Net user myself, but the code will be much the same in any language, and it could look something like this in C/C++:

Code: [Select]
mixer = BASS_Mixer_StreamCreate(freq, chans, BASS_STREAM_DECODE|BASS_MIXER_END); // create a mixer that ends when its sources do

// create decoders for each of the files
for (a = 0; a < num_files, a++)
decoder[a] = BASS_StreamCreateFile(FALSE, filename[a], 0, 0, BASS_SAMPLE_FLOAT|BASS_STREAM_DECODE);

// plug the first 2 files into the mixer (assuming they're the main ones)
BASS_Mixer_StreamAddChannel(mixer, decoder[0], 0);
BASS_Mixer_StreamAddChannel(mixer, decoder[1], 0);

// set syncs to add the other files to the mix
for (a = 0; a < num_events; a++) {
QWORD pos = BASS_ChannelSeconds2Bytes(mixer, event[a].time); // get start position in bytes
BASS_ChannelSetSync(mixer, BASS_SYNC_POS|BASS_SYNC_MIXTIME, pos, EventSyncProc, (void*)a); // set a sync at that position in the mix
}

BASS_Encode_Start(mixer, "output.wav", BASS_ENCODE_PCM, NULL, 0); // set a WAV writer on the mixer

// processing loop
while (1) {
BYTE buf[20000]; // processing buffer
int r = BASS_ChannelGetData(mixer, buf, sizeof(buf)); // process the mixer
if (r == -1) break; // done
}

BASS_Encode_Stop(mixer); // close the WAV writer

...

void CALLBACK EventSyncProc(HSYNC handle, DWORD channel, DWORD data, void *user)
{
int e = (int)user; // the event number
HSTREAM dec = decoder[event[e].file]; // the decoder handle
BASS_ChannelSetPosition(dec, 0, BASS_POS_BYTE); // rewind the decoder in case it has been played before
BASS_Mixer_StreamAddChannel(channel, dec, 0); // plug it into the mixer
}

This is assuming that you have an "event" array that tells what file to play at what time. Please see the documentation for details on the mentioned functions.

Fabacon

  • Posts: 3
Re: Combining multiple files to one & stream
« Reply #2 on: 19 Aug '17 - 21:24 »
Thanks a lot, Ian. It looks doable. I will let you know when I managed.  ;D

Fabacon

  • Posts: 3
Re: Combining multiple files to one & stream
« Reply #3 on: 7 Sep '17 - 20:33 »
I have translated most of the C++ code to C#, but I bump into a few problems. Maybe you can help me in this?

- First I get this exception: [EntryPointNotFoundException: Kan ingangspunt met de naam BASS_Mixer_StreamCreate niet vinden in DLL bassmix.]
(It says of course it can't find the entrypoint with the name 'BASS_Mixer_StreamCreate' in DLL bassmix). But Intellisense in Visual Studio gives me this...

- Secondly I have no clue what to do with the CALLBACK part of the code. I have tried to make it work but without any luck.

I hope you can have a look (or anyone with a C# background) and help me on the right direction.

Here is my code:

Code: [Select]
   
private void test()
        {
            var freq = 44100;
            var chans = 2;
            var files = new string[] { "c:/soundtest/background.mp3", "c:/soundtest/in-1.mp3", "c:/soundtest/in-2.mp3" };
            var decoders = new List<int>();
            var mixer = Un4seen.Bass.AddOn.Mix.BassMix.BASS_Mixer_StreamCreate(freq, chans, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_END); // create a mixer that ends when its sources do
            var seconds = new List<double>();
            seconds.Add(3d);
            seconds.Add(6d);
            seconds.Add(10d);
            seconds.Add(22d);



            // create decoders for each of the files
            for (int a = 0; a < files.Length; a++)
            {
                decoders[a] = Bass.BASS_StreamCreateFile(files[a], 0, 0, BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE);
            }

            // plug the first 2 files into the mixer (assuming they're the main ones)
            Un4seen.Bass.AddOn.Mix.BassMix.BASS_Mixer_StreamAddChannel(mixer, decoders[0], 0);
            Un4seen.Bass.AddOn.Mix.BassMix.BASS_Mixer_StreamAddChannel(mixer, decoders[1], 0);

            // set syncs to add the other files to the mix
            for (int a = 0; a < seconds.Count; a++)
            {
                long pos = Bass.BASS_ChannelSeconds2Bytes(mixer, seconds[a]); // get start position in bytes
                Bass.BASS_ChannelSetSync(mixer, BASSSync.BASS_SYNC_POS | BASSSync.BASS_SYNC_MIXTIME, pos, EventSyncProc, IntPtr.Zero); // set a sync at that position in the mix
            }

            BassEnc.BASS_Encode_Start(mixer, "c:/soundtest/background.mp3", BASSEncode.BASS_ENCODE_PCM, null, IntPtr.Zero); // set a WAV writer on the mixer

            // processing loop

            while (true)
            {
                byte[] buf = new byte[20000]; // processing buffer
                int r = Bass.BASS_ChannelGetData(mixer, buf, sizeof(byte)); // process the mixer
                if (r == -1)
                {
                    break; // done
                }
            }

            BassEnc.BASS_Encode_Stop(mixer); // close the WAV writer
        }


        private void EventSyncProc(int handle, int channel, int data, IntPtr user)
        {
            int e = (int)user; // the event number
            HSTREAM dec = decoder[event[e].file]; // the decoder handle
            Un4seen.Bass.BASS_ChannelSetPosition(dec, 0, Bass.BASS_POS_BYTE); // rewind the decoder in case it has been played before
            Un4seen.Bass.AddOn.Mix.BassMix.BASS_Mixer_StreamAddChannel(channel, dec, 0); // plug it into the mixer
        }

Ian @ un4seen

  • Administrator
  • Posts: 20393
Re: Combining multiple files to one & stream
« Reply #4 on: 8 Sep '17 - 14:35 »
- First I get this exception: [EntryPointNotFoundException: Kan ingangspunt met de naam BASS_Mixer_StreamCreate niet vinden in DLL bassmix.]
(It says of course it can't find the entrypoint with the name 'BASS_Mixer_StreamCreate' in DLL bassmix). But Intellisense in Visual Studio gives me this...

I'm not a .Net user myself, but I think you only need to use a "BassMix." prefix (rather than "Un4seen.Bass.AddOn.Mix.BassMix.") in the BASSmix function calls. If it still isn't working, have you put the BASSMIX.DLL file alongside your EXE and the BASS.DLL file? If you don't have that, you can get it from the BASSmix package, which you can download from the BASS page.

- Secondly I have no clue what to do with the CALLBACK part of the code. I have tried to make it work but without any luck.

Callback functions require a "delegate" in .Net. Please see the "Callbacks and Delegates" section of the "Interoperating with Unmanaged Code" page in the BASS.Net documentation for details on that.