Author Topic: Trying to create a radio station  (Read 743 times)

nudrick

  • Posts: 8
Trying to create a radio station
« on: 17 Feb '18 - 00:13 »
Hello Everybody

First of all, thanks for the support that you can give me.

Related to my question, I am using Bass.net to try to create a radio station with IceCast but I dont know if the features that I want to do are possible to be made.
Until now, I am able to create a MountPoint and to stream a mp3 file to IceCast without problems. What I need to do are the following tasks:
  • Stream all the mp3 files that I have in a folder
  • Fade in/out, in different times (seconds), each mp3 file
So basicaly what I need to do is a SourceClient.
Anybody did something similar? Can you share some information about this particular feature, in case it will be possible to be done.

Example:
- Audio1.mp3 will fade in from second 0 to 8 and fade out from second 120 to 130
- Audio2.mp3 will fade in from second 10 to 20 and fade out from second 120 to 130

In certain part there has to be a crossfade, like audio1 is finishing and audio2 will start exactly when audio1 is fading out.


Thanks

Ian @ un4seen

  • Administrator
  • Posts: 21208
Re: Trying to create a radio station
« Reply #1 on: 19 Feb '18 - 16:10 »
The easiest way to do what would be with a mixer, using the BASSmix add-on. The encoder would be set on the mixer, and the files would be played through it. You can use volume envelopes for the fading-in/out. It could look something like this:

Code: [Select]
typedef struct {
char *filename; // the file to play
float start; // start time in seconds
float fadein; // fade-in length in seconds
float fadeout; // fade-out length in seconds
} source;

source sources[num_sources] = { // array of sources
...
};

...

mixer = BASS_Mixer_StreamCreate(freq, chans, BASS_MIXER_END); // create the mixer

// add the sources to the mix
for (n = 0; n < num_sources; n++) {
DWORD decoder = BASS_StreamCreateFile(sources[n].filename, FALSE, 0, 0, BASS_STREAM_DECODE|BASS_SAMPLE_FLOAT); // create a decoder for the n'th file
QWORD start = BASS_ChannelSeconds2Bytes(mixer, sources[n].start); // convert start time to bytes
BASS_Mixer_StreamAddChannelEx(mixer, decoder, BASS_MIXER_NORAMPIN|BASS_STREAM_AUTOFREE, start, 0); // plug the source into the mix at that position
float length = BASS_ChannelBytes2Seconds(decoder, BASS_ChannelGetLength(decoder, BASS_POS_BYTE)); // get the source's length in seconds
// setup an envelope to fade-in and fade-out
BASS_MIXER_NODE nodes[4];
nodes[0].pos = 0;
nodes[0].val = 0; // start silent
nodes[1].pos = BASS_ChannelSeconds2Bytes(mixer, sources[n].fadein); // fade-in end position
nodes[1].val = 1; // full volume after fade-in
nodes[2].pos = BASS_ChannelSeconds2Bytes(mixer, length - sources[n].fadeout); // fade-out start position
if (nodes[2].pos < nodes[1].pos) nodes[2].pos = nodes[1].pos; // make sure the fades don't overlap
nodes[2].val = 1; // still full volume
nodes[3].pos = BASS_ChannelSeconds2Bytes(mixer, length); // fade-out end position
nodes[3].val = 0; // silent after fade-out
BASS_Mixer_ChannelSetEnvelope(decoder, BASS_MIXER_ENV_VOL, nodes, 4); // apply the envelope to the source
}

encoder = BASS_Encode_Start(mixer, ...); // set an encoder on the mixer
BASS_Encode_CastInit(encoder, ...); // setup casting on the encoder
BASS_ChannelPlay(mixer, FALSE); // start the mixer

Please see the docuementation for details on the mentioned functions. Note the sources will be freed when the mixer reaches the end of them, due to the BASS_STREAM_AUTOFREE flag. If you might stop/cancel the mixer before then, you should retain the handles returned by BASS_StreamCreateFile and free them via BASS_StreamFree.

nudrick

  • Posts: 8
Re: Trying to create a radio station
« Reply #2 on: 23 Feb '18 - 16:00 »
Hey Ian

Thank you very much! Now it's working perfectly!

One more question. Is there anyway to keep the broadcast always open? Because I have checked that when the mix stops, the broadcast also is going to finish.


Thanks

Ian @ un4seen

  • Administrator
  • Posts: 21208
Re: Trying to create a radio station
« Reply #3 on: 23 Feb '18 - 17:47 »
You can replace the BASS_MIXER_END flag with BASS_MIXER_NONSTOP in the BASS_Mixer_StreamCreate call, to have the mixer continue playing (silence) at the end of its sources.

nudrick

  • Posts: 8
Re: Trying to create a radio station
« Reply #4 on: 24 Feb '18 - 15:25 »
Thanks for your support, Ian.

It worked good for one file. I am using BASS_ChannelSetSync to add one file when the previous one has finished. But if I change from BASS_MIXER_END to BASS_MIXER_NONSTOP the mixer will stop after the first file.

What do you think?

Ian @ un4seen

  • Administrator
  • Posts: 21208
Re: Trying to create a radio station
« Reply #5 on: 26 Feb '18 - 15:23 »
Are you setting a BASS_SYNC_END sync on the mixer? If so, that indeed won't be triggered if the BASS_MIXER_END flag isn't used, as the mixer will never end. If you want to do that and also play silence when there are no more sources, then you could change the mixer's flags in the final sync call, something like this:

Code: [Select]
void CALLBACK EndSyncProc(HSYNC handle, DWORD channel, DWORD data, void *user)
{
if (nextsource) // got another source to play
BASS_Mixer_StreamAddChannel(channel, nextsource, 0); // add it to the mixer
else // no more sources, continue with silence
BASS_ChannelFlags(channel, BASS_MIXER_NONSTOP, BASS_MIXER_NONSTOP|BASS_MIXER_END); // set BASS_MIXER_NONSTOP and unset BASS_MIXER_END
BASS_ChannelSetPosition(channel, 0, BASS_POS_BYTE); // reset the mixer to continue (it's currently ended)
}

nudrick

  • Posts: 8
Re: Trying to create a radio station
« Reply #6 on: 10 May '18 - 18:18 »
Hello Ian

Thanks for your help. I had everything working perfectly. The only problem is that I lose the connection when I finish playing my playlist. Right now I have this code:

Code: [Select]
            mixer = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_MIXER_END);
           
            decoder[0] = Bass.BASS_StreamCreateFile(files[0], 0, 0, BASSFlag.BASS_STREAM_DECODE);
           
            BassMix.BASS_Mixer_StreamAddChannel(mixer, decoder[0], BASSFlag.BASS_MIXER_NORAMPIN | BASSFlag.BASS_STREAM_AUTOFREE);

            // setup an envelope to fade-in and fade-out
            BASS_MIXER_NODE[] nodes = new BASS_MIXER_NODE[4];
            //SILENT
            nodes[0].pos = Bass.BASS_ChannelSeconds2Bytes(mixer, mix_audio.ListFiles[0].StartFadeIn);
            nodes[0].val = 0; // start silent

            //FADE-IN END AND FULL VOLUME
            nodes[1].pos = Bass.BASS_ChannelSeconds2Bytes(mixer, mix_audio.ListFiles[0].StopFadeIn);
            nodes[1].val = mix_audio.ListFiles[0].StartVolume;

            //FADE-OUT START AND FULL VOLUME
            nodes[2].pos = Bass.BASS_ChannelSeconds2Bytes(mixer, mix_audio.ListFiles[0].StartFadeOut);
            nodes[2].val = mix_audio.ListFiles[0].StartVolume;

            //FADE-OUT END AND LOW VOLUME
            nodes[3].pos = Bass.BASS_ChannelSeconds2Bytes(mixer, mix_audio.ListFiles[0].StopFadeOut);
            nodes[3].val = mix_audio.ListFiles[0].StopVolume;

            BassMix.BASS_Mixer_ChannelSetEnvelope(decoder[0], BASSMIXEnvelope.BASS_MIXER_ENV_VOL, nodes, 4); // apply the envelope to the source
            Bass.BASS_ChannelSetSync(mixer, BASSSync.BASS_SYNC_END, 0, CurrentTrackEnded2, new IntPtr(0)); // set a mixtime END sync on the mixer
            Bass.BASS_ChannelPlay(mixer, false); // start the mixer
            Bass.BASS_ChannelSetAttribute(mixer, BASSAttribute.BASS_ATTRIB_VOL, 1);

            EncoderLAME LameObj = createLameEncoder(mixer);

            string IceCastMountPoint    = ConfigurationManager.AppSettings["IceCastMountPoint"].ToString();
            string IceCastServer        = ConfigurationManager.AppSettings["IceCastServer"].ToString();
            int IceCastPort             = Convert.ToInt32(ConfigurationManager.AppSettings["IceCastPort"].ToString());
            string IceCastUserName      = ConfigurationManager.AppSettings["IceCastUserName"].ToString();
            string IceCastPassword      = ConfigurationManager.AppSettings["IceCastPassword"].ToString();
            string IceCastStreamName    = ConfigurationManager.AppSettings["IceCastStreamName"].ToString();
            string IceCastStreamGenre   = ConfigurationManager.AppSettings["IceCastStreamGenre"].ToString();
            string IceCastSongTitle     = ConfigurationManager.AppSettings["IceCastSongTitle"].ToString();

            ICEcast IcecastServer       = new ICEcast(LameObj);
            IcecastServer.MountPoint    = "/" + IceCastMountPoint;
            IcecastServer.ServerAddress = IceCastServer;
            IcecastServer.ServerPort    = IceCastPort;
            IcecastServer.Username      = IceCastUserName;
            IcecastServer.Password      = IceCastPassword;
            IcecastServer.StreamName    = IceCastStreamName;
            IcecastServer.StreamGenre   = IceCastStreamGenre;
            IcecastServer.PublicFlag    = false;
            IcecastServer.SongTitle     = IceCastSongTitle;
            server = IcecastServer;

            BroadCast cBroadCast = new BroadCast(IcecastServer);
            cBroadCast.AutoReconnect = true;
            cBroadCast.ReconnectTimeout = 15;
            cBroadCast.AutoConnect();

and then the callback is this:

Code: [Select]
            currentfile++;
            if (currentfile < decoder.Length)
            {
                decoder[currentfile] = Bass.BASS_StreamCreateFile(files[currentfile], 0, 0, BASSFlag.BASS_STREAM_DECODE);
                BassMix.BASS_Mixer_StreamAddChannel(mixer, decoder[currentfile], BASSFlag.BASS_MIXER_NORAMPIN | BASSFlag.BASS_STREAM_AUTOFREE);

                // setup an envelope to fade-in and fade-out
                BASS_MIXER_NODE[] nodes = new BASS_MIXER_NODE[4];

                //SILENT
                nodes[0].pos = mix_audio.ListFiles[currentfile].StartFadeIn;
                nodes[0].val = 0; // start silent

                //FADE-IN END AND FULL VOLUME
                nodes[1].pos = Bass.BASS_ChannelSeconds2Bytes(mixer, mix_audio.ListFiles[currentfile].StopFadeIn);
                nodes[1].val = mix_audio.ListFiles[currentfile].StartVolume;

                //FADE-OUT START AND FULL VOLUME
                nodes[2].pos = Bass.BASS_ChannelSeconds2Bytes(mixer, mix_audio.ListFiles[currentfile].StartFadeOut);
                nodes[2].val = mix_audio.ListFiles[currentfile].StartVolume;

                //FADE-OUT END AND LOW VOLUME
                nodes[3].pos = Bass.BASS_ChannelSeconds2Bytes(mixer, mix_audio.ListFiles[currentfile].StopFadeOut);
                nodes[3].val = mix_audio.ListFiles[currentfile].StopVolume;

                BassMix.BASS_Mixer_ChannelSetEnvelope(decoder[currentfile], BASSMIXEnvelope.BASS_MIXER_ENV_VOL, nodes, 4); // apply the envelope to the source
                Bass.BASS_ChannelSetSync(mixer, BASSSync.BASS_SYNC_END, 0, CurrentTrackEnded2, new IntPtr(0)); // set a mixtime END sync on the mixer

                Bass.BASS_ChannelPlay(mixer, false);
            }
            else {
                //mixer = 0;
                Bass.BASS_ChannelFlags(mixer, BASSFlag.BASS_MIXER_NONSTOP, BASSFlag.BASS_MIXER_END);
                Bass.BASS_ChannelSetPosition(mixer, 0, BASSMode.BASS_POS_BYTES);

            }

With that code the playlist will work perfectly, but when all the playlist will stop playing, the Mountpoint is going to be destroyed and I want to keep it always open. I have tried using BASS_MIXER_NONSTOP for the mixer but then I won't be able to reach the callback.

What do you think I can do?


Thanks

Ian @ un4seen

  • Administrator
  • Posts: 21208
Re: Trying to create a radio station
« Reply #7 on: 11 May '18 - 14:16 »
The BASS_ChannelFlags call doesn't look quite right. Try this:

Code: [Select]
                Bass.BASS_ChannelFlags(mixer, BASSFlag.BASS_MIXER_NONSTOP, BASSFlag.BASS_MIXER_END | BASSFlag.BASS_MIXER_NONSTOP);

Note BASS_MIXER_NONSTOP is included in both of the "flags" and "mask" parameters, to set that flag on the mixer.

nudrick

  • Posts: 8
Re: Trying to create a radio station
« Reply #8 on: 19 May '18 - 19:44 »
Hello Ian

Finally, I have created a NON STOP mixer like this:
Code: [Select]
mixerNonStop = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_MIXER_NONSTOP);
And the I add my streams in this way:
Code: [Select]
BassMix.BASS_Mixer_StreamAddChannel(mixerNonStop, decoder[0], BASSFlag.BASS_MIXER_NORAMPIN | BASSFlag.BASS_STREAM_AUTOFREE);
Now the Mountpoint is not going to finish until I close my application and that is perfect  :)

My question is, can I add another mixer to the NON STOP one? That "child" mixer will have some envelopes and I also need to implement the BASS_ChannelSetSync when the "child" mixer will finish. Right now I am doing everything with just the stream and I cannot apply the envelopes.

Which flags do I need to set for this "child" mixer in order to add it to the NON STOP one?


Thanks!