Tutorials/MP3Terminal/Page2
From NeoAxis Engine Wiki
Contents |
Media Player Terminal: Hello World
Step 1: The C# code
In this section, we will create a very basic C# class where we will implement out Bass.NET functionality and an even simpler gui file that has one play button, so we can test we have everything linked properly.
Let's start by looking at the code and see what's going on from there
using System;
using Un4seen.Bass;
using Engine.FileSystem;
namespace GameEntities
{
public static class MediaPlayer
{
private static int stream = 0;
private static string file;
public static void Initialize()
{
BassNet.Registration("angrywasp@iinet.net.au", "2X314252229298");
Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero, null);
}
public static void Play()
{
file = VirtualFileSystem.GetRealPathByVirtual("Sounds/MP3/The Day That Never Comes.mp3");
stream = Bass.BASS_StreamCreateFile(file, 0, 0, BASSFlag.BASS_STREAM_AUTOFREE);
if (stream != 0)
Bass.BASS_ChannelPlay(stream, false);
}
}
}
First thing to note is that we are using a static class. Since Bass.NET is a collection of static classes and methods it makes sense that we would implement Bass.NET as a static class.
At the moment, we have only 2 methods:
- Initialize()
- Play()
When using Bass.NET we need to make a call to BassNET.Registration and Bass.BASS_Init before doing anything.
Remember in that last section when i told you to get a license key? Well you use that in the BassNET.Registration call. It is a very simple process to not have the nag screen popping up at you. If there are any calls to the Bass.NET API before the one made to BassNet.Registration, we will get the nag screen, so we structure our code so that it is the first call made (We will see this later in the logic editor).
Straight after that is a call to Bass.BASS_Init. We must call this to be able to use Bass, but after the call to BassNet.Registration to avoid the nag screen. Bass.BASS_Init has a few parameters:
- int device: The device to use for playback. -1 is the default windows sound device. 0 is no sound and the rest is up to you to discover as they will be different on every computer (or non-existent)
- int freq: The sample rate of the audio. 44100 is the mp3 default, so we will use that.
- BassInit flags: just some flags to tell Bass how to handle the audio output. Since we are not doing anything special we just use BASSInit.BASS_DEVICE_DEFAULT, but there are other options like using 8-bit audio, mono, or for special speaker assignments.
- IntPtr win: This is the handle to the window the player sits in. The documentation states to use IntPtr.Zero for the current foreground window, so that sounds like the one to use.
- Object/Guid (depending on overload) clsid: As the docs state, 'Class identifier of the object to create, that will be used to initialize DirectSound' There is no harm in setting it as null, it will just use the default.
So that's what the Initialize method does. When we use this class in the logic editor, we will call this first to register our copy of Bass.NET and to prepare our audio device.
The other method we have is Play() at this point we are just getting a mp3 file and starting playback, nothing fancy and no error checking. I have an mp3 called "The Day That Never Comes" from Metallica's new album 'Death Magnetic' being held in Data/Sounds/MP3. Later on, we will get these file paths from a config file and populate a list in the gui. Also, you don't need to have your music in NeoAxis's data directory. You can load music from anywhere, provided you have the absolute path of the file. This prevents duplicating files on your computer and saves some disk space.
To get music file ready for playback, we make a call to Bass.BASS_StreamCreateFile and assign that to an int variable 'stream'. If the call to Bass.BASS_StreamCreateFile is successful, we get a value other than 0, if it fails we are left with 0 so we can use this premise for some basic error checking, in that if stream is not 0 we can play it.
Bass.BASS_StreamCreateFile has some parameters which we should look at:
- string file: The path of the file to play
- Int64 offset: The offset to begin playback. Using 0 starts the track from the beginning.
- Int64 length: Set how much of the track to play. 0 plays the entire track
- BassFlag flags: Determine how to process the track fro playback. We are using BASS_STREAM_AUTOFREE so that the stream resources are automatically freed when the track ends. We will add more later when we start to implement equalizers and DSP effects. The docs have a list of all the available flags and what they do.
Then finally after wh have created the stream and verified it was successful we play it. Bass.BASS_ChannelPlay has only 2 parameters, the file to play and a bool indicating if it should restart. We would set this to true to start from the beginning and false, if we were just pausing the track.
So after all that, we have the basis for playing a track. Next up we make a gui and get this going in the logic editor.
Step 2: The Terminal GUI
OK, if you haven't done so, fire up the resource editor. For those who don't know how to create a gui follow these steps:
- Right click the directory you want the gui in and select 'New Resource'
- In the New Resource dialog, select 'UI Model' and hit 'Continue' then 'Next'
- Give your gui a name and select 'Base Templates -> Control' as the base UI model
- Hit 'Next' then 'Finish' and you have a gui
So we are now going to add a button to it which will be our play button. Follow these steps if you don't know how to add a control:
- Make sure the parent of your control has a check next it then right click and select 'Create New Control'
- Then in the New Control dialog, select 'Data -> Gui -> Controls -> DefaultButton.gui' and hit OK to add one to your gui
Then we just select the control and move it to the center of the screen. While we have it selected we want to change 2 properties: Text: Change to "Play" or some other similar labels that indicates this is the button that will play music Name: Change to "btnPlay" or whatever. I will be using the name btnPlay later on, so if you call it something else, keep that in mind
So now we have a rather ordinary looking gui with a single button in the middle of it. It will become much more complex as time goes on.
Next we are onto the logic editor, where we will hook it all up (and hopefully get some music)
Step 3: The Logic Editor
One thing i should point out from that start is that we will be using the script view of the logic editor. I personally find this much easier than the designer view and for the purposes of the tutorial. It is easier to show code in this tutorial from the script view, rather than screen shots of the designer view. With that said, it's time to get started.
OK if you haven't saved your gui, firstly, bad NeoAxis user, go to the corner (just kidding), do that and close the resource editor. Open up the map editor and open whatever map you want to add mp3 control to.
First thing is to add a terminal. Terminals can be found in 'Entity Types -> Types -> Dynamic -> Terminal'. Once added you need to provide a gui for the terminal via the 'GameGUIObject -> InitialControl' property. Just select the gui you made and just like magic (or some good coding) the gui is on the terminal. At this point you can run your map and click the button, but nothing will happen. So lets do something about that.
First off we need to make a logic class for the terminal. The easiest way to do that is to double click on the 'Entity -> LogicClass' property of the terminal. This will automatically create a logic class of the right type and open the logic editor for you. In case you don't know, the other way to open the logic editor is via the 'World -> Logic Editor' menu item.
First off we need to create a "PostCreated" method, so we can get handles to the gui objects and initialize Bass. To use one of the override methods in your logic class follow the diagram below.
OK so now in our class we should have a method called "PostCreated". It should have opened for editing when you created it, but if not, just double click it.
In this method we will start with this code:
//get a handle to our play button EButton btnPlay = Owner.MainControl.Controls["btnPlay"] as EButton; //assign a click event handler to that button btnPlay.Click += btnPlay_Click; //Initialize Bass MediaPlayer.Initialize();
One thing i should point out to all those unfamiliar is the 'Owner'. Owner refers to the control to which you have assigned the logic class.
The comments are pretty self explanatory. People familiar with using gui objects will notice a slight difference between how we get gui objects in our code and how we do it in the logic editor. In code (i.e. our game) we would use something like
EControl MainControl = ControlDeclarationManager.Instance.CreateControl("guiFile.gui");
EButton btnPlay = MainControl.Controls["btnPlay"] as EButton;
Whereas in the logic editor we only need
EButton btnPlay = Owner.MainControl.Controls["btnPlay"] as EButton;
A small distinction. Basically, where we would create the control then use the reference to that to get the individual gui objects, that has already been done for the terminal via this bit of code in GameGUIObject.CreateMainControl
if( controlManager != null && !string.IsNullOrEmpty( initialControl ) )
{
mainControl = ControlDeclarationManager.Instance.CreateControl( initialControl );
if( mainControl != null )
controlManager.Controls.Add( mainControl );
}
So basically same code, just cuts out a step for using terminals.
Now that I have come back from my (sort of pointless) tangent, lets proceed.
So PostCreated gets the button out of the terminal into a usable reference. We then have added a Click event handler to that button and finally Initialized Bass.NET through the call to Initialize (which we looked at in Step 1).
Next thing to do is to create a method which will server as our event handler.
Creating methods is slightly different to just overriding them. Rather than selecting an method from the list, we create a new one by selecting 'Method -> Script Type'. Then we get the 'Method Definition' dialog. Here we just type in the name of the method (i.e. 'btnPlay_Click'), set the return type to 'void' then add a parameter by clicking on the 'New' button next to the (empty) list of parameters, which will bring up the 'Method Parameter' dialog
For the Click event handler we only need one parameter:
- EButton sender
To do this we select EButton from the Type drop down and set the name as 'sender' and hit OK.
So now we should have 2 methods. open btnPlay_Click for editing and place this single line of code in
MediaPlayer.Play();
That will of course play the song we set in the code when we click the button. Save your map and test it out. If all went well, you should have an mp3 of your choosing playing. If not try these
- Is your path to your mp3 set correctly?
- Is your volume turned up? (believe me, it isn't a stupid question)
- Have you copied the Bass.dll to your NeoAxis bin directory?
- Have you built your source code? (Again, not as stupid a question as one might think)
If you have answered YES to all the above questions, Feel free to ask on the forums. It is imperative that you have a song playing, so you have all the groundwork done before proceeding.
Conclusion
By this stage you should have an uneventful media player that plays one single song from a hard coded file path and do nothing else. That's OK. We will make it better. The point of this exercise is to get the groundwork together for the rest of the series.
In the next section we will add a playlist and the ability to move through that playlist and start playback by clicking on list items.
angrywasp



