19

I'm a student of Computer Science. I have a final semester Project to develop a short game in graphics along with the sound.

Muhammad Usman Bashir
  • 1,441
  • 2
  • 14
  • 43
John Talbott
  • 215
  • 1
  • 2
  • 4
  • 1
    [WAV info](https://ccrma.stanford.edu/courses/422/projects/WaveFormat/) – Michael Mar 07 '14 at 14:45
  • 5
    To get a worthwhile and helpful response, rather than comment on searching the web, you need to indicate what you've tried. That is, show some sample code that tries to load your .mp3 file. Have you tied to use any existing libraries (but failed). These are more helpful. – wmorrison365 Mar 07 '14 at 14:46
  • 3
    p.s. You could check out how these libraries do it: http://en.cppreference.com/w/cpp/links/libs – wmorrison365 Mar 07 '14 at 14:48
  • 1
    This question already has answers in SO. You could search for them, the most popular ones seem to be FMOD and SDL, both of which have been used in many games – PALEN Jan 11 '15 at 15:35
  • 1
    @Michael: Your link is down. – Tara Dec 17 '15 at 20:00
  • 2
    @Dudeson: Thanks. I believe [this](http://soundfile.sapp.org/doc/WaveFormat/) page is identitical. – Michael Dec 18 '15 at 07:53
  • 1
    @Michael: Ah, yes it is. Thanks. – Tara Dec 19 '15 at 19:34

6 Answers6

68

First of all, write the following code:

#include <Mmsystem.h>
#include <mciapi.h>
//these two headers are already included in the <Windows.h> header
#pragma comment(lib, "Winmm.lib")

To open *.mp3:

mciSendString("open \"*.mp3\" type mpegvideo alias mp3", NULL, 0, NULL);

To play *.mp3:

mciSendString("play mp3", NULL, 0, NULL);

To play and wait until the *.mp3 has finished playing:

mciSendString("play mp3 wait", NULL, 0, NULL);

To replay (play again from start) the *.mp3:

mciSendString("play mp3 from 0", NULL, 0, NULL);

To replay and wait until the *.mp3 has finished playing:

mciSendString("play mp3 from 0 wait", NULL, 0, NULL);

To play the *.mp3 and replay it every time it ends like a loop:

mciSendString("play mp3 repeat", NULL, 0, NULL);

If you want to do something when the *.mp3 has finished playing, then you need to RegisterClassEx by the WNDCLASSEX structure, CreateWindowEx and process it's messages with the GetMessage, TranslateMessage and DispatchMessage functions in a while loop and call:

mciSendString("play mp3 notify", NULL, 0, hwnd); //hwnd is an handle to the window returned from CreateWindowEx. If this doesn't work, then replace the hwnd with MAKELONG(hwnd, 0).

In the window procedure, add the case MM_MCINOTIFY: The code in there will be executed when the mp3 has finished playing.

But if you program a Console Application and you don't deal with windows, then you can CreateThread in suspend state by specifying the CREATE_SUSPENDED flag in the dwCreationFlags parameter and keep the return value in a static variable and call it whatever you want. For instance, I call it mp3. The type of this static variable is HANDLE of course.

Here is the ThreadProc for the lpStartAddress of this thread:

DWORD WINAPI MP3Proc(_In_ LPVOID lpParameter) //lpParameter can be a pointer to a structure that store data that you cannot access outside of this function. You can prepare this structure before `CreateThread` and give it's address in the `lpParameter`
{
    Data *data = (Data*)lpParameter; //If you call this structure Data, but you can call it whatever you want.
    while (true)
    {
        mciSendString("play mp3 from 0 wait", NULL, 0, NULL);
        //Do here what you want to do when the mp3 playback is over
        SuspendThread(GetCurrentThread()); //or the handle of this thread that you keep in a static variable instead
    }
}

All what you have to do now is to ResumeThread(mp3); every time you want to replay your mp3 and something will happen every time it finishes.

You can #define play_my_mp3 ResumeThread(mp3); to make your code more readable.

Of course you can remove the while (true), SuspendThread and the from 0 codes, if you want to play your mp3 file only once and do whatever you want when it is over.

If you only remove the SuspendThread call, then the sound will play over and over again and do something whenever it is over. This is equivalent to:

mciSendString("play mp3 repeat notify", NULL, 0, hwnd); //or MAKELONG(hwnd, 0) instead

in windows.

To pause the *.mp3 in middle:

mciSendString("pause mp3", NULL, 0, NULL);

and to resume it:

mciSendString("resume mp3", NULL, 0, NULL);

To stop it in middle:

mciSendString("stop mp3", NULL, 0, NULL);

Note that you cannot resume a sound that has been stopped, but only paused, but you can replay it by carrying out the play command. When you're done playing this *.mp3, don't forget to:

mciSendString("close mp3", NULL, 0, NULL);

All these actions also apply to (work with) wave files too, but with wave files, you can use "waveaudio" instead of "mpegvideo". Also you can just play them directly without opening them:

PlaySound("*.wav", GetModuleHandle(NULL), SND_FILENAME);

If you don't want to specify an handle to a module:

sndPlaySound("*.wav", SND_FILENAME);

If you don't want to wait until the playback is over:

PlaySound("*.wav", GetModuleHandle(NULL), SND_FILENAME | SND_ASYNC);
//or
sndPlaySound("*.wav", SND_FILENAME | SND_ASYNC);

To play the wave file over and over again:

PlaySound("*.wav", GetModuleHandle(NULL), SND_FILENAME | SND_ASYNC | SND_LOOP);
//or
sndPlaySound("*.wav", SND_FILENAME | SND_ASYNC | SND_LOOP);

Note that you must specify both the SND_ASYNC and SND_LOOP flags, because you never going to wait until a sound, that repeats itself countless times, is over!

Also you can fopen the wave file and copy all it's bytes to a buffer (an enormous/huge (very big) array of bytes) with the fread function and then:

PlaySound(buffer, GetModuleHandle(NULL), SND_MEMORY);
//or
PlaySound(buffer, GetModuleHandle(NULL), SND_MEMORY | SND_ASYNC);
//or
PlaySound(buffer, GetModuleHandle(NULL), SND_MEMORY | SND_ASYNC | SND_LOOP);
//or
sndPlaySound(buffer, SND_MEMORY);
//or
sndPlaySound(buffer, SND_MEMORY | SND_ASYNC);
//or
sndPlaySound(buffer, SND_MEMORY | SND_ASYNC | SND_LOOP);

Either OpenFile or CreateFile or CreateFile2 and either ReadFile or ReadFileEx functions can be used instead of fopen and fread functions.

Hope this fully answers perfectly your question.

  • 9
    Wow, I can't believe this answer has not really been noticed so far! Such a good and detailed resource for people like me who want an easy .mp3 sound implementation in their C++ code! – Sossenbinder Jan 01 '16 at 17:21
  • 1
    `*.mp3` must be replaced with the full path and filename to the mp3 file. – Paul Ogilvie Mar 08 '19 at 14:26
  • 1
    Header file `mciapi.h` does not exist on my VS2008 system; however, the required definitions are included in `MMSystem.h` (which is in turn included in `Windows.h`). – Paul Ogilvie Mar 08 '19 at 14:28
  • I believe this is WIndows only – Adrian Maire Jul 10 '20 at 17:06
  • 1
    excuse me, but mciSendString("play ...") without mciSendString("... wait") does nothing, the program ends as soon as it starts, to me at least, do I have to do something more? – platinoob_ Nov 05 '20 at 13:18
  • @AdrianMaire You do realise the question was specifically asking for Windows. – Nikita Demodov Apr 30 '21 at 07:25
  • @NikitaDemodov, VC++ can target non-Windows platforms, also, new developers tend to put their IDE tag without really understanding the absurdity of making platform-dependent code. – Adrian Maire Apr 30 '21 at 09:49
8

http://sfml-dev.org/documentation/2.0/classsf_1_1Music.php

SFML does not have mp3 support as another has suggested. What I always do is use Audacity and make all my music into ogg, and leave all my sound effects as wav.

Loading and playing a wav is simple (crude example):

http://www.sfml-dev.org/tutorials/2.0/audio-sounds.php

#include <SFML/Audio.hpp>
...
sf::SoundBuffer buffer;
if (!buffer.loadFromFile("sound.wav")){
    return -1;
}
sf::Sound sound;
sound.setBuffer(buffer);
sound.play();

Streaming an ogg music file is also simple:

#include <SFML/Audio.hpp>
...
sf::Music music;
if (!music.openFromFile("music.ogg"))
    return -1; // error
music.play();
DCurro
  • 1,797
  • 1
  • 15
  • 16
  • 1
    works for me by using the precompiled binaries – V-SHY Dec 04 '14 at 02:28
  • possibly Windows version. Unix needs sudo aptitude install libcsfml-dev then see https://github.com/SFML/CSFML/tree/master/include/SFML/Audio for instructions. why are answers closed? This is an important and clear question. Try sfSoundBuffer* buffer = sfSoundBuffer_createFromFile("/mysounds/morse.wav"); sfSound*sound = sfSound_create(); sfSound_setBuffer(sound, buffer); sfSound_play(sound); – DragonLord Jan 21 '21 at 21:59
5

If you want to play the *.mp3 or *.wav file, i think the easiest way would be to use SFML.

Xardaska
  • 149
  • 1
  • 7
  • 7
    Please keep in mind though, that SFML doesn't support the MP3 format, due to licensing issues. However you can just as well use the lesser known but equally good OGG format. – Lukas Aug 15 '14 at 10:18
4

Try with simple c++ code in VC++.

#include <windows.h>
#include <iostream>
#pragma comment(lib, "winmm.lib")

int main(int argc, char* argv[])
{
std::cout<<"Sound playing... enjoy....!!!";
PlaySound("C:\\temp\\sound_test.wav", NULL, SND_FILENAME); //SND_FILENAME or SND_LOOP
return 0;
}
Kulamani
  • 509
  • 6
  • 13
3

I would use FMOD to do this for your game. It has the ability to play any file mostly for sounds and is pretty simple to implement in C++. using FMOD and Dir3ect X together can be powerful and not that difficult. If you are familiar with Singleton classes I would create a Singleton class of a sound manager in your win main cpp and then have access to it whenever to load or play new music or sound effects. here's an audio manager example

    #pragma once

#ifndef H_AUDIOMANAGER
#define H_AUDIOMANAGER

#include <string>
#include <Windows.h>
#include "fmod.h"
#include "fmod.hpp"
#include "fmod_codec.h"
#include "fmod_dsp.h"
#include "fmod_errors.h"
#include "fmod_memoryinfo.h"
#include "fmod_output.h"

class AudioManager
{
public:
    // Destructor
    ~AudioManager(void);

    void Initialize(void);  // Initialize sound components
    void Shutdown(void);    // Shutdown sound components

    // Singleton instance manip methods
    static AudioManager* GetInstance(void);
    static void DestroyInstance(void);

    // Accessors
    FMOD::System* GetSystem(void)
        {return soundSystem;}

    // Sound playing
    void Play(FMOD::Sound* sound);  // Play a sound/music with default channel
    void PlaySFX(FMOD::Sound* sound);   // Play a sound effect with custom channel
    void PlayBGM(FMOD::Sound* sound);   // Play background music with custom channel

    // Volume adjustment methods
    void SetBGMVolume(float volume);
    void SetSFXVolume(float volume);

private:
    static AudioManager* instance;  // Singleton instance
    AudioManager(void);  // Constructor

    FMOD::System* soundSystem;  // Sound system object
    FMOD_RESULT result;
    FMOD::Channel* bgmChannel;  // Channel for background music
    static const int numSfxChannels = 4;
    FMOD::Channel* sfxChannels[numSfxChannels]; // Channel for sound effects
};

#endif
Josh
  • 188
  • 1
  • 12
  • 2
    That's not really related to op's qestion but could you explain why you have separate shutdown method instead of relying on the destructor? – jaho Mar 09 '14 at 18:15
  • 2
    because with as many components as a sound system should have you can handle all the objects of the sound system there and not in the destructor because the destructor will destroy the sound manager but none of the objects created from say the sound class, just its own class. – Josh Mar 09 '14 at 18:41
  • 2
    Well you can put the same code you put into `shutdown()` method into destructor. That's really the purpose of the destructor, to release all the resources held by an object. I often see this two-step destruction kind of design, but can never understand the reasoning behind it. Why not use the default facilities C++ provides? Besides that you can always use smart pointers and not have to worry about explicitly releasing the resources. I just don't see the benefits of a separate `shutdown()` function. – jaho Mar 09 '14 at 21:00
2

Use a library to (a) read the sound file(s) and (b) play them back. (I'd recommend trying both yourself at some point in your spare time, but...)

Perhaps (*nix):

Windows: DirectX.

user3392484
  • 1,929
  • 9
  • 9