Introduction
The ability of playing music on a PC has always been one of the most used features computers ever offered. It is why I use my computer mostly, anyway. I guess most of you, while using IRC and mIRC, like to listen to music in the over popular MP3 format because of its quality, transferability, and of course, low disk memory requirements. Since version 5.8, mIRC (read - Khaled) has implemented the ability of playing MP3 media files directly from mIRC, WITHOUT using any external programs of any kind. Now, don't you think that playing music insides mIRC is much more versatile and fun, than using another program to do the job. An internal media player could also be a great addition in your scripts. During this tutorial, I'll try to point out the main structure lines, which I think every media player should offer.
What mIRC Offers
Besides the ability of playing WAVE and MIDI files, since version, 5.8, mIRC offers the ability of playing MP3 media files. Supposedly, mIRC could play MP1 and MP2 files, but Khaled has not implicitly stated that ability, so I won't take it for granted.
Playing sounds (read - media files) can be achieved by using the /splay command, with the proper combination of switches. mIRC's sound playing ability also includes some sound handling identifiers, which will also be used within the examples this tutorial has to offer.
Sound Handling
Sound Commands
As explained before, playing sounds can be achieved while using the /splay command, with all of its switches. As taken from the mIRC help file :
/splay -wmpq [filename | stop | pause | resume | seek | skip] [pos]
This command will play the specified sound under filename, which can be a .WAV, .MID, or .MP3 file. As for the playing switches, w = WAVE, m = MIDI, p = MP3, and q = QUEUE for playing. If you don't specify a folder, the sound folders in the Sound Requests dialog are searched.
You can use stop to stop a currently playing sound, like /splay stop, or /splay -w stop, to stop just wave files. You can use pause, resume, seek and pos to manipulate sound actions. You can use skip to skip the current playing song, and jump to the next in the queue list, as specified using the queue parameter.
Note: The pause, resume, seek and pos parameters can ONLY be used with MP3 files. Since we will be making a media player to play WAVE's and MIDI's as well as MP3's, this is a good point to remember mIRC's limitations concerning this matter.
Sound Identifiers
The sound identifiers we will be using are the following :
$inmp3, $inmidi, $inwave
All of these identifiers will return $true if the specified sound type is being played. Quite useful in the position when you have a sound file playing, and you can not determine it's type. For example, you may want to display an ID3 tag, which is only found in MP3's and you could have a WAVE playing, which would possibly generate an error, or in the best case scenario - do nothing. That is why, you should ALWAYS check for the sound type playing BEFORE performing any type related actions.
Note: While mIRC allows you to play multiple files at once, try to limit the file number to one, since that way you could avoid multiple scripting complications. On the other hand, since MP3's use your computer's WAVE output channel, the end result of playing multiple files at once would probably be garbage.
The $inmp3 identifier, unlike the two other ones, supports additional properties: fname - filename currently being played, pos - the position of the file being played, and length - length of the current file in milliseconds. The $inwave and the $inmidi identifier only support the fname property.
$mp3(filename)
This identifier returns information about the specified MP3 filename, as set up in its ID3 tag. If the field in he ID3 tag about the specified property you requested is empty, the identifier will return $null. The supported properties are: album, title, artist, year, comment, genre, track, length, version, bitrate, variable, sample, mode, copyright, private and crc.
Sound Events
And, of course, the sound events raised would be :
On MIDIEND, On WAVEEND, On MP3END
The On MIDIEND, On WAVEEND, and On MP3END events trigger when mIRC finishes playing a sound.
Format: On <level>:MP3END:<commands>
Note: These events will not trigger if you use /splay to play another sound or to stop a sound being played, they will only trigger if the sound finishes playing completely. The use of these events should be quite simple. For example, you could use them to establish a repeat function, or to notify the user about the end of the song being played.
Main Features Of The Player
Here, I should explain the main features a player should have, considering the current mIRC features and capabilities. If we leave out the more than standard GUI, along with the main play, pause, stop & eject functions, as well as repeat, that still leaves us with features such as the name of the song being played, its length, and of course, the current position of the song being played. With MP3 files, there is also the ID3 tag display.
In the examples this tutorial will provide, the main features of the media player will be :
- standard GUI (dialog based or a picture window)
- play, pause, stop, eject, seek functions
- song title display, along with total length and current position
Custom MP3 Identifiers
In order to achieve the above given functions, especially the song title display and the song length and position display, we will need to establish some custom identifiers, one of which will determine the song title display, and another one to return a 00:00 format of the song length and position.
Note: The identifiers code, along with the other examples which will be given below, will be placed at the end of the tutorial as a whole, to be used in your scripts. All of the code parts represented here should be placed in the remote section of mIRC's editor, preferably in a separate script file.
Song Position Identifier - $mplayer.length
The main purpose of this identifier is to return a 00:00 format of the input parameter, which, as a standard, is a numeric value containing an amount of milliseconds, no matter if it is the total song length or the current position of the song being played.
alias mplayer.length {
var %mplayer.len $int($calc($1 / 1000))
var %mplayer.min $int($calc(%mplayer.len / 60))
var %mplayer.sec $calc(%mplayer.len - (%mplayer.min * 60))
if (%mplayer.min < 10) { set %mplayer.min 0 $+ %mplayer.min }
if (%mplayer.sec < 10) { set %mplayer.sec 0 $+ %mplayer.sec }
set %mplayer.len %mplayer.min $+: $+ %mplayer.sec
return %mplayer.len
}
Usage: $mplayer.length(102903) will return 01:42, where 102903 is the number of milliseconds resolved with the built-in mIRC identifier $inmplayer.length.
Song Title Identifier - $mplayer.entry
The main purpose of this identifier is to return a full length song title which could then be used as a song title display within the media player. Since the media player will be able to play WAVE's and MIDI's as well as MP3's, it would be appropriate to notify the user of the sound type being played.
alias mplayer.entry {
var %mplayer.entry
if (.wav isin $longfn($1)) {
set %mplayer.entry $nopath($longfn($1))
set %mplayer.entry $remove(%mplayer.entry,.,wav)
set %mplayer.entry %mplayer.entry - WAVE File
return %mplayer.entry
}
if (.mid isin $longfn($1)) {
set %mplayer.entry $nopath($longfn($1))
set %mplayer.entry $remove(%mplayer.entry,.,mid)
set %mplayer.entry %mplayer.entry - MIDI File
return %mplayer.entry
}
if (.mp3 isin $1) {
set %mplayer.entry $mp3($1).artist - $mp3($1).title
}
if (.mp3 isin $1) && ($mp3($1).artist == $null) || ($mp3($1).title == $null) {
set %mplayer.entry $remove($nopath($longfn($1)),.mp3)
}
return %mplayer.entry
}
Note: You have probably noticed the use of the $longfn identifier, which returns the long version of the filename under Windows 95, 98 & 2000. The main use of it is necessary because of mIRC's inability to properly manipulate filenames containing spaces. Therefore, when using the $mplayer.entry identifier, and every aspect of the /splay command, make sure you supply the short version of the filename, by converting it with the $shortfn identifier. Of course, you wouldn't want to have a song playing displayed as Song~1, which is why I use the $longfn identifier here.
Note: Another thing you have to remember when using the $mplayer.entry custom identifier is that you ALWAYS have to supply the full filename including the file path, because of the use of the $mp3 identifier. If you miss out the file path, mIRC will look for the file in the folders you have specified in the Sound Requests dialog.
How It Works: First, the identifier checks for the filename extension. If it is .wav or .mid, it strips out the file path and resolves the filename, while adding the appropriate file type suffix. Therefore, if we have a WAVE or a MIDI file :
$mplayer.entry(C:\Songs\WaveSong.wav) will return: WaveSong - WAVE File
$mplayer.entry(C:\Songs\MidiSong.mid) will return: MidiSong - MIDI File
On the other hand, if we have a MP3 file, it will first check for the existence of the ID3 tag. If so, it will return the song display in the format: Artist - Title. Therefore :
$mplayer.entry(C:\Songs\ExampleSong.mp3) will return: Example Maker - Example Song, if the ID3 tag is present, and the artist field holds Example Maker, and the title field holds Example Song.
On the other hand, if the ID3 tag is missing, or the artist and the title fields are empty, it will resolve the filename removing the file path and the file extension.
$mplayer.entry(C:\Songs\AnotherSong.mp3) will return: AnotherSong, if the ID3 tag is not present, or the artist field or the title field is empty.
Setting Up The Player GUI
Since one of the features of the played explained before would be the standard GUI, this is where we will begin with the making of the player itself, since I have so far introduced you to the basics of sound playing in mIRC and we have set up the necessary identifiers.
The player GUI (Graphical User Interface) could be set up using a dialog, or a picture window. Since the picture windows tend to be more difficult and less understandable, this tutorial will create a dialog based media player.
Following the main feature lines specified earlier for the player itself, and at the same time explaining the parts of the dialog window, the dialog table will hold :
- 2 text boxes - one for the song display, and the other one for the length and the position display
- 6 command buttons - for the player functions: play, pause, stop, eject and 2 seek buttons
- 1 check box - for the repeat function
So, the dialog table should now look like the following :
dialog mplayer {
title "mIRC Media Player"
size -1 -1 127 38
option dbu
box "",1,-3 -3 300 4
text "",2,3 4 150 7
text "",3,3 12 150 7
button "<<",5,3 25 12 11
button ">",6,17 25 12 11
button "| |",7,31 25 12 11
button "[ ]",8,45 25 12 11
button ">>",9,59 25 12 11
button "Eject",10,73 25 20 11
check "Repeat",11,100 25 24 11,push
button "",12,0 0 0 0, cancel
}
And then, we would need an alias in order to load up the dialog window :
alias mplayer { if ($dialog(mplayer) == $null) dialog -md mplayer mplayer }
Note: Before proceeding with the player functions, I'd like to explain the dialog table a bit, and why I have designed it like it is. Since this is not a dialog tutorial, I will suppose you have mastered the basics of dialog, and continue with the parts of the dialog table.
The dialog table has been designed using dbu (default base units), in order to make sure it would look exactly the same on every system. Te first item, the box, is just a separator. The text boxes (ID 2 & 3), have been placed in order to hold the title of the song being played, and the time length and position display.
Next are the 6 command buttons (ID 5,6,7,8,9 & 10), holding the functions for play, pause, stop, seek and eject. I've tried to use symbols in order to display the proper commands, but you can, (if you decide) use button captions instead of the given symbols.
And finally, the check box (ID 11) holds the player's repeat function.
The lowest placed command button (ID 12), holds the cancel function for the dialog.
The set up alias to load up the player dialog, uses a simple if statement to check if it is not already active. If not, it loads up the dialog window and sets it up as a desktop window.
Note: It is the -d switch in the dialog command which sets up the dialog as a desktop window. If you wish, you can leave it out, but you will have an on top window INSIDE mIRC, and you will lose the minimize button.
Playing A Song
Hopefully, by now you have set up the player window, and tested the custom identifiers I've discussed earlier. The next thing to discuss is (finally!) playing a song in our media player. In order to do so, we need to locate a media file (MP3, WAVE or MIDI), resolve the song title display, the song length and use the /splay command to play the file. Therefore, we need to set up an alias which will perform the necessary checks (such as the dialog existence, file existence etc.) and then play the song.
alias mplayer.play {
if ($dialog(mplayer) == $null) { return }
if ($1 != $null) || ($exists($1) == $true) {
set %mplayer.file $1
goto playfile
}
if (%mplayer.file == $null) { return }
:playfile
if (.mp3 !isin %mplayer.file) { did -b mplayer 5,9 }
else { did -e mplayer.player 5,9 }
splay %mplayer.file
did -ra mplayer 2 $mplayer.entry(%mplayer.file)
did -ra mplayer 3 00:00 / $mplayer.length(%mplayer.file)
return
}
Note: You may have noticed the use of the %mplayer.file custom variable. The use of it is quite necessary, because of the repeat function we will be discussing later on.
Our alias now is capable of playing the song, no matter its file type, and displaying its title and length. The next thing we need to do is edit the On *:DIALOG:mplayer:sclick event in order to activate the alias for playing the song. Therefore :
On *:DIALOG:mplayer:sclick:6:{ mplayer.play }
You may have noticed that the song keeps playing even after the dialog has been closed. To fix that :
On *:DIALOG:mplayer:sclick:12:{ splay stop }
Up till now, we have used an alias that required a manual entry of the song - its path and filename. That is why, we need to supply an identifier that will open up a browse window, establish the existence of a file, and then return it's short version. So far so good :
alias mplayer.eject {
set %mplayer.file $file="Please Select A Media File ..." "C:\*.*"
if (%mplayer.file == $null) { return }
set %mplayer.file $shortfn(%mplayer.file)
if ($dialog(mplayer) != $null) {
did -ra mplayer 2 $mplayer.entry(%mplayer.file)
did -ra mplayer 3 00:00 / $mplayer.length($mp3(%mplayer.file).length)
}
return %mplayer.file
}
The next thing to do is to set up a sclick dialog event to load a file. So :
On *:DIALOG:mplayer:sclick:10:{ .timer 1 0 mplayer.eject }
Note: In this example, I have used a timer command in order to trick mIRC who does not allow the use of identifiers inside dialogs. This way, the timer will trigger only once, and execute the command. Therefore, the file will be loaded and the song will be initialized, if found.
Stopping & Pausing Songs
By now, we have browsed, found, opened a song and played it in the media player. Sometime now, you'd want the song to STOP playing. Aha! Here, we set up the main aliases to stop and pause the songs. First, we will set up a mplayer.stop alias :
alias mplayer.stop {
splay -p stop
splay -w stop
splay -m stop
unset %mplayer.pause
}
Note: I have decided to use separate /splay lines in case you have multiple songs playing at the same time, within mIRC.
To trigger the mplayer.stop alias from within the mIRC media player dialog :
On *:DIALOG:mplayer:sclick:8:{ mplayer.stop }
And that's about it.
On the other hand, pausing and resuming the songs would require a setting up of a separate mplayer.pause alias, and a slight modification of the mplayer.play alias. I will first set up the mplayer.pause alias, and then explain the modifications in the previous one.
alias mplayer.pause {
if ($inmp3 == $false) { return }
splay pause
set %mplayer.pause 1
did -b mplayer 7
}
And, to trigger the mplayer.pause alias :
On *:DIALOG:mplayer:sclick:7:{ mplayer.pause }
As you may have noticed, disabling the pause button marked the pausing of the song. In order to resume the playback of the current song, we will need to slightly modify the prior mplayer.play alias. I will discuss only the code changes in the following code segment, as I am displaying the alias in full :
alias mplayer.play {
if ($dialog(mplayer) == $null) { return }
if (%mplayer.pause == 1) { goto proceed }
if ($1 != $null) || ($exists($1) == $true) {
set %mplayer.file $1
goto playfile
}
if (%mplayer.file == $null) { return }
:playfile
if (.mp3 !isin %mplayer.file) { did -b mplayer 5,9 }
else { did -e mplayer 5,9 }
splay %mplayer.file
unset %mplayer.pause
did -ra mplayer 2 $mplayer.entry(%mplayer.file)
did -ra mplayer 3 00:00 / $mplayer.length($mp3(%mplayer.file).length)
return
:proceed
splay resume
did -e mplayer 7
set %mplayer.pause 0
}
This should do it, and you should now have a working media player with play, stop, pause & eject functions.
Seeking Through Songs
Unlike for the WAVE & MIDI playing capabilities, Khaled has enabled the /splay command to perform seeking through both directions of MP3 encoded songs. That is how, while using /splay seek, we will make the seek buttons on our media player work.
Before we proceed, we must make sure that the seek buttons won't be able to be used on WAVE's or MIDI's, since /splay seek does not work on those. So we have, using the enable and the disable commands in the mplayer.play alias.
As for the seek aliases, we will create 1 alias which will be triggered by a parameter which can hold two values: forward and reverse, in order to move through the playback process. I will discuss the code on the way :
alias mplayer.seek {
if ($inmp3 == $false) || ($1 == $null) || ($dialog(mplayer) == $null) { return }
var %mplayer.sfactor 10
if ($1 == reverse) {
var %mplayer.seek $calc($inmp3.pos - (%mplayer.sfactor * 1000))
if (%mplayer.seek < 0) { return }
goto seek
}
if ($1 == forward) {
var %mplayer.seek $calc($inmp3.pos + (%mplayer.sfactor * 1000))
if (%mplayer.seek > $inmp3.length) { return }
goto seek
}
splay seek %mplayer.seek
return
}
And, to trigger the seek alias from the seek buttons :
On *:DIALOG:mplayer:sclick:5:{ mplayer.seek reverse }
On *:DIALOG:mplayer:sclick:9:{ mplayer.seek forward }
Which should finally do it.
Note: If you wish to change the seek interval, just change the %mplayer.sfactor variable. In these examples, it is set at the value of 10 seconds. You are free to modify it to your needs.
Repeating Songs
As said, our little media player should have a repeat function. Basically, achieving this is no problem. This is why, I have introduced you to the On MP3END, MIDIEND & WAVEEND events. The only thing to do here, is to place a playback command to play the current file as soon as it's playback finishes. So, if we have in mind that the filename is stored with the %mplayer.file variable, and the ID of the check box in the dialog with the repeat function is 11, we would have :
On *:MP3END:{ if ($dialog(mplayer) != $null) && ($did(mplayer,11).state == 1) mplayer.play }
On *:WAVEEND:{ if ($dialog(mplayer) != $null) && ($did(mplayer,11).state == 1) mplayer.play }
On *:MIDIEND:{ if ($dialog(mplayer) != $null) && ($did(mplayer,11).state == 1) mplayer.play }
Note: Even though quite handy, this feature can cause a lot of headaches in your scripts, if you prefer to use a lot of sound notifications. That is why, you SHOULD NOT forget to check IF the media player is active.
Displaying Song Position
And to perform the last feature I've set as a goal of this tutorial, we will use the $mplayer.length identifier. All we have to do is simply make sure that the playing song is a MP3 song, and to enter it's current position ($inmp3.pos) as the parameter of the $mplayer.length identifier. So, the following alias should be placed at the end of the mplayer.play, mplayer.stop and the mplayer.pause aliases:
alias mplayer.position {
if ($dialog(mplayer) == $null) { return }
did -ra mplayer 3 $mplayer.length($inmp3.pos) / $mplayer.length($mp3(%mplayer.file).length)
}
Note: The mplayer.position alias will be called through a /timer command, with a set up interval of 1 second. A smaller time interval is not needed, since the position display is updated per second.
The Media Player
As agreed, here is the full code, along with all the examples used in this tutorial, sorted out & ready to go.
alias mplayer.length {
var %mplayer.len $int($calc($1 / 1000))
var %mplayer.min $int($calc(%mplayer.len / 60))
var %mplayer.sec $calc(%mplayer.len - (%mplayer.min * 60))
if (%mplayer.min < 10) { set %mplayer.min 0 $+ %mplayer.min }
if (%mplayer.sec < 10) { set %mplayer.sec 0 $+ %mplayer.sec }
set %mplayer.len %mplayer.min $+: $+ %mplayer.sec
return %mplayer.len
}
alias mplayer.entry {
var %mplayer.entry
if (.wav isin $longfn($1)) {
set %mplayer.entry $nopath($longfn($1))
set %mplayer.entry $remove(%mplayer.entry,.,wav)
set %mplayer.entry %mplayer.entry - WAVE File
return %mplayer.entry
}
if (.mid isin $longfn($1)) {
set %mplayer.entry $nopath($longfn($1))
set %mplayer.entry $remove(%mplayer.entry,.,mid)
set %mplayer.entry %mplayer.entry - MIDI File
return %mplayer.entry
}
if (.mp3 isin $1) {
set %mplayer.entry $mp3($1).artist - $mp3($1).title
}
if (.mp3 isin $1) && ($mp3($1).artist == $null) || ($mp3($1).title == $null) {
set %mplayer.entry $remove($nopath($longfn($1)),.mp3)
}
return %mplayer.entry
}
alias mplayer.play {
if ($dialog(mplayer) == $null) { return }
if (%mplayer.pause == 1) { goto proceed }
.timermplayer off
if ($1 != $null) || ($exists($1) == $true) {
set %mplayer.file $1
goto playfile
}
if (%mplayer.file == $null) { return }
:playfile
if (.mp3 !isin %mplayer.file) { did -b mplayer 5,9 }
else { did -e mplayer 5,9 }
splay %mplayer.file
unset %mplayer.pause
.timermplayer 0 1 mplayer.position
did -ra mplayer 2 $mplayer.entry(%mplayer.file)
did -ra mplayer 3 00:00 / $mplayer.length($mp3(%mplayer.file).length)
return
:proceed
splay resume
did -e mplayer 7
set %mplayer.pause 0
.timermplayer 0 1 mplayer.position
}
alias mplayer.eject {
set %mplayer.file $file="Please Select A Media File ..." "C:\*.*"
if (%mplayer.file == $null) { return }
set %mplayer.file $shortfn(%mplayer.file)
if ($dialog(mplayer) != $null) {
did -ra mplayer 2 $mplayer.entry(%mplayer.file)
did -ra mplayer 3 00:00 / $mplayer.length($mp3(%mplayer.file).length)
}
return %mplayer.file
}
alias mplayer.stop {
.timermplayer off
splay -p stop
splay -w stop
splay -m stop
unset %mplayer.pause
did -ra mplayer 3 $mplayer.length($inmp3.pos) / $mplayer.length($mp3(%mplayer.file).length)
}
alias mplayer.pause {
if ($inmp3 == $false) { return }
splay pause
set %mplayer.pause 1
.timermplayer off
did -b mplayer 7
}
alias mplayer.seek {
if ($inmp3 == $false) || ($1 == $null) || ($dialog(mplayer) == $null) { return }
var %mplayer.sfactor 10
if ($1 == reverse) {
var %mplayer.seek $calc($inmp3.pos - (%mplayer.sfactor * 1000))
if (%mplayer.seek < 0) { return }
goto seek
}
if ($1 == forward) {
var %mplayer.seek $calc($inmp3.pos + (%mplayer.sfactor * 1000))
if (%mplayer.seek > $inmp3.length) { return }
goto seek
}
:seek
splay seek %mplayer.seek
did -ra mplayer 3 $mplayer.length($inmp3.pos) / $mplayer.length($mp3(%mplayer.file).length)
return
}
alias mplayer.position { if ($dialog(mplayer) != $null) did -ra mplayer 3 $mplayer.length($inmp3.pos) / $mplayer.length($mp3(%mplayer.file).length) }
dialog mplayer {
title "mIRC Media Player"
size -1 -1 127 38
option dbu
box "",1,-3 -3 300 4
text "",2,3 4 150 7
text "",3,3 12 150 7
button "<<",5,3 25 12 11
button ">",6,17 25 12 11
button "| |",7,31 25 12 11
button "[ ]",8,45 25 12 11
button ">>",9,59 25 12 11
button "Eject",10,73 25 20 11
check "Repeat",11,100 25 24 11,push
button "",12,0 0 0 0,cancel
}
alias mplayer { if ($dialog(mplayer) == $null) dialog -md mplayer mplayer }
On *:DIALOG:mplayer:init:0:{
if (%mplayer.file != $null) { did -ra mplayer 2 $mplayer.entry(%mplayer.file) }
}
On *:DIALOG:mplayer:sclick:5:{ mplayer.seek reverse }
On *:DIALOG:mplayer:sclick:6:{ mplayer.play }
On *:DIALOG:mplayer:sclick:7:{ mplayer.pause }
On *:DIALOG:mplayer:sclick:8:{ mplayer.stop }
On *:DIALOG:mplayer:sclick:9:{ mplayer.seek forward }
On *:DIALOG:mplayer:sclick:10:{ .timer 1 0 mplayer.eject }
On *:DIALOG:mplayer:sclick:12:{ splay stop }
On *:MP3END:{ if ($dialog(mplayer) != $null) && ($did(mplayer,11).state == 1) { mplayer.play } }
On *:WAVEEND:{ if ($dialog(mplayer) != $null) && ($did(mplayer,11).state == 1) { mplayer.play } }
On *:MIDIEND:{ if ($dialog(mplayer) != $null) && ($did(mplayer,11).state == 1) { mplayer.play } }
Note: Just copy the code in full, and paste it in a clean file in the Remote Section.
Conclusion
I hope I've succeeded in what I've tried to do here. By now, you should be able to create your own media player in mIRC, using these and your own custom identifiers. Of course, having finished this tutorial, does not give the final product in the looks of every more than average media player.
Here, the basics of playing, pausing, resuming and seeking of songs have been shown. You have the total freedom to modify the given examples and improve them.
What you could do as a next step is an ID3 tag display window, a play list editor, a volume mixing control window, channel playback etc., but that is something I leave for you to decide.
Note: The examples used in this tutorial have been extracted from Soul Blade B3 by INSIDES and slightly modified to server the purpose of the tutorial.