Jim Lawless' Blog


A Command-Line MP3 Player for Windows

Originally published on: Sun, 02 Aug 2009 03:44:19 +0000

Please note! If you're having difficulties compiling the C source code presented below, please see my post: Compiling C from the Command Line with Pelles C

( See also http://www.mailsend-online.com/blog/play-mp3-files-with-python-on-windows.html ... a newer post that describes how to use the same technique presented below to play MP3's in Python scripts. )

I was thinking about writing a scriptable MP3 player today and realized that I really didn't know how to cause an MP3 to play on a recent version of Windows. I chose to create a command-line MP3 utility named cmdmp3.

I had used the sndPlaySound() API call to play WAV files, but I had assumed that playing an MP3 wouldn't be quite that easy. I found that I needed to use the Media Control Interface API via the mciSendString() function.

I'm no stranger to writing C code to use Windows API calls. I expected that I'd have to fill out a bunch of data structures with a DWORD in the front to determine the given structure's size and assumed that I'd have to learn a lot of new bitwise flags.

I was pleasantly surprised; the mciSendString() function accepts a text command string with parameters. Instead of having to learn a constant to represent a WAIT flag, I simply needed to append the word "Wait" to the end of the string that plays the MP3.

To play an MP3, cmdmp3 issues three MCI commands:

Close All
Open filename Type MPEGVideo Alias theMP3
Play theMP3 Wait

The first command closes active media that's playing. I assume that this is only within the same process, as I was able to launch two concurrent invocations of cmdmp3.exe and heard both MP3's playing simultaneously.

The next command was the Open command. Note that the type is specified as MPEGVideo even though audio only will be played. the Alias option causes the symbol theMP3 to act as a sort of handle variable for use with the Play command.

The filename specified in the open cannot contain spaces as the MCI string parser will assume that the latter parts of such a filename are parameters. In order to accommodate common file paths with spaces in them, cmdmp3 calls the GetShortPathName() API function to obtain an equivalent filename with all of the spaces removed.

The final command that causes the MP3 to be heard is the Play command. I added the "Wait" option at the end of the play string to prevent the API from returning while the MP3 plays. This would have caused the cmdmp3 process to terminate. Terminating cmdmp3 will halt the playing MP3.

After writing cmdmp3, I realized that others might enjoy using it, but might not want a console window to be displayed while the MP3 plays. You'll see an alternate version of the source called cmdmp3win that provides a window-only version of the player.

The program cmdmp3win.exe does not create its own window ... it simply tries to play the MP3, then terminates.

The command-line syntax is spartan; the first parameter of each program is used as the filename. Filenames with spaces in their name or path should be enclosed in double-quotes.

cmdmp3 "c:\my songs\something.mp3" or cmdmp3win "c:\my songs\something.mp3"

cmdmp3.c


// cmdmp3
// A command-line MP3 player for Windows
// (console-mode version)
//
// License: MIT / X11
// Copyright (c) 2009 by James K. Lawless
// jimbo@radiks.net http://www.radiks.net/~jimbo
// http://www.mailsend-online.com
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include <windows.h>
#include <stdio.h>
#include <string.h>

#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"kernel32.lib")

void sendCommand(char *);

int main(int argc,char **argv) {
   char shortBuffer[MAX_PATH];
   char cmdBuff[MAX_PATH + 64];
   printf("cmdmp3\n");
   printf("Command-line MP3 player\n");
   printf("by Jim Lawless\n\n");
   
   if(argc<2) {
      fprintf(stderr,"Syntax:\n\tcmdmp3 \"c:\\path to file\\file.mp3\"\n");
      return 1;
   }
      // Get the shortened path because the MCI string interpreter uses spaces
      // as a separator. If spaces appear in the commands, parts of the filename
      // would be interpreted as paramters to the given command.
   GetShortPathName(argv[1],shortBuffer,sizeof(shortBuffer));
   if(!*shortBuffer) {
      fprintf(stderr,"Cannot shorten filename \"%s\"\n",argv[1]);
      return 1;
   }
   sendCommand("Close All");

   sprintf(cmdBuff,"Open %s Type MPEGVideo Alias theMP3",shortBuffer);
   sendCommand(cmdBuff);

   sendCommand("Play theMP3 Wait");
   return 0;
}

   // Send a string to the Media Control Interface
   // If an error occurs, display it and the string
   // that produced the error.
void sendCommand(char *s) {
   int i;
   i=mciSendString(s,NULL,0,0);
   if(i) {
         fprintf(stderr,"Error %d when sending %s\n",i,s);
   }
}

cmdmp3win.c


// cmdmp3win
// A command-line MP3 player for Windows
// (window-mode version)
//
// License: MIT / X11
// Copyright (c) 2009 by James K. Lawless
// jimbo@radiks.net http://www.radiks.net/~jimbo
// http://www.mailsend-online.com
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.



#include <windows.h>
#include <string.h>

#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"kernel32.lib")
#pragma comment(lib, "user32.lib")

char msg[256];

extern int __argc;
extern char ** __argv;


void sendCommand(char *);

int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow ) {

   char shortBuffer[MAX_PATH];
   char cmdBuff[MAX_PATH + 64];
   
   if(__argc<2) {
      sprintf(msg,"Syntax:\n\tcmdmp3win \"c:\\path to file\\file.mp3\"\n");
      MessageBox(NULL,msg,"cmdmp3win",MB_OK);
      return 1;
   }
      // Get the shortened path because the MCI string interpreter uses spaces
      // as a separator. If spaces appear in the commands, parts of the filename
      // would be interpreted as paramters to the given command.
   GetShortPathName(__argv[1],shortBuffer,sizeof(shortBuffer));
   if(!*shortBuffer) {
      sprintf(msg,"Cannot shorten filename \"%s\"\n",__argv[1]);
      MessageBox(NULL,msg,"cmdmp3win",MB_OK);
      return 1;
   }
   sendCommand("Close All");

   sprintf(cmdBuff,"Open %s Type MPEGVideo Alias theMP3",shortBuffer);
   sendCommand(cmdBuff);

   sendCommand("Play theMP3 Wait");
   return 0;
}

   // Send a string to the Media Control Interface
   // If an error occurs, display it and the string
   // that produced the error.
void sendCommand(char *s) {
   int i;
   i=mciSendString(s,NULL,0,0);
   if(i) {
         sprintf(msg,"Error %d when sending %s\n",i,s);
         MessageBox(NULL,msg,"cmdmp3win",MB_OK);
   }
}

The source and EXE files for cmdmp3 and cmdmp3win can be found here.

http://www.mailsend-online.com/wp/cmdmp3.zip

Unless otherwise noted, all code and text entries are Copyright 2009 by James K. Lawless


Views expressed in this blog are those of the author and do not necessary reflect those of the author's employer.


Previous post: Checking Shift States with DEBUG
Next post:A Quine in Forth


About Jim ...