Play a MIDI voice (Dev C++ console program)

vegaseat 3 Tallied Votes 3K Views Share

You can access the sound chip to play midi voices using winmm.lib, or in case of Dev C++ the libwinmm.a library. There are 128 midi voices to pick from, anything from the Acoustic Grand Piano = 0 to the Gunshot = 127.

vb6exp32 commented: i greatly appreciate the "play a MIDI voice" snippet provided.. it worked perfect in my dev c ++ +0
Metalpeich commented: Great solution, worked perfectly +0
// sound a tugboat toot using a midi voice from the winmm.lib
// in case of Dev C++ link with libwinmm.a via
// Project>>Project Options>>Parameters>>Add Lib>>libwinmm.a
// BCX generated C code painstakingly modified for Dev C++ 
//
// Sound(Frequency,Duration[,Volume,Voice,Tempo])
// Volume = 0 to 127 (off to loudest)
// Voice = 0 to 127 (Shanai = 111, Tuba = 58, Accordion = 21)
// more midi voices: 
// Rock Organ = 18, Marimba = 12, Steel String Guitar = 25
// Choir Aahs = 52, Alto Sax = 65, Bird Tweet = 123, Sitar = 104
// FX 8 (sci-fi) = 103, FX 3 (crystal) = 98, Glockenspiel = 9 
//
// a Dev-C++ tested Console Application by  vegaseat  21nov2004

#include <cmath>
#include <windows.h>
#include <mmsystem.h>

using namespace std;

#define SNDQUE 10000

typedef struct _soundtype
{
  double  Freq;
  int     Dura;
  int     Vol;
  int     Voice;
  double  Tempo;
  int     sndTid;
} soundtype, *LPSOUNDTYPE;

static soundtype  SndPmtr[SNDQUE+1];
static int        gTenter;
static int        gTwait;
static int        gTexit;
static int        gTarray;
static BOOL       gTsig;
static HANDLE     gSThread = NULL;

double  Round (double,int);
double  Abs (double);
int     Sound (float,int=0,int=127,int=0,float=1);
// changed this from int PlaySnd(void) to:
DWORD WINAPI PlaySnd (LPVOID);


int main()
{
  // Tugboat whistle sound 95 hertz, 2000ms, 127 = loud, 111 = Shanai
  // experiment with your own sounds, it's fun ...
  Sound(95,2000,127,111);  // 2 second blast 
  Sound( 1,1000,  0,111);  // 1 second of silence 
  Sound(95,2000,127,111);  // 2 second blast 
  Sound( 1,1000,  0,111);  // 1 second of silence 
  Sound(95,2000,127,111);  // 2 second blast
      
  // wait till que is empty
  while(Sound(0) != 0)
  {
    Sleep(10);
  }
 
  return 0;
}


double Round (double n, int d)
{
  return (floor((n)*pow(10.0,(d))+0.5)/pow(10.0,(d)));
}


double Abs (double a)
{
  if (a < 0)  return -a;
  return  a;
}


int Sound (float Freq,int Dura,int Vol,int Voice,float Tempo)
{
  DWORD  dwThreadId;
  
  if (Freq == 0 && Dura < 1) return gTenter-gTexit;
  // silence
  if (Freq == 0) Vol = 0;
  if (Dura < 5) Dura = 5;
  gTenter++;
  gTsig = FALSE;
  if (gTenter >= SNDQUE)
  { 
    gTarray = gTenter % SNDQUE+1;
  }
  else 
  {               
    gTarray=gTenter;
  }
  SndPmtr[gTarray].Freq = Freq;
  SndPmtr[gTarray].Dura = Dura;
  SndPmtr[gTarray].Tempo = Tempo;
  SndPmtr[gTarray].Vol = Vol;
  SndPmtr[gTarray].Voice = Voice;
  SndPmtr[gTarray].sndTid = gTenter;
  if (gSThread == NULL && (Freq == Abs(Freq) || Freq == 0))
  {
      // "PlaySnd" needs casting (void *)
      gSThread = CreateThread(NULL,0,PlaySnd,(void *)"PlaySnd",0,&dwThreadId);
      Sleep(1);
      return 0;
  }
  if (Freq != Abs(Freq))
  {
    if (Freq == -1)
    {
      Freq = 0;
      SndPmtr[gTarray].Vol=0;
    }
    SndPmtr[gTarray].Freq=Abs(Freq);
    gTsig=TRUE;
    while(gSThread!=NULL)
    {
      Sleep(10);
    }
    gTexit = gTenter-1;
    gTwait = gTenter-1;
    gTsig = FALSE;
    return PlaySnd(0);  // needs some kind of argument
  }
  return 0;
}


DWORD WINAPI PlaySnd (LPVOID)
{
  soundtype  LocSndPar;
  int  lTarray;
  
  while(gTenter > gTexit && gTsig == FALSE)
  {
    gTwait++;
    if (gTwait >= SNDQUE)
      lTarray = gTwait % SNDQUE+1;
    else
      lTarray = gTwait;
    LocSndPar = SndPmtr[lTarray];
    int Note = 0;
    int Phrase = 0;
    HMIDIOUT hMidi;
    midiOutOpen(&hMidi,(UINT)-1,0,0,CALLBACK_NULL);
    midiOutShortMsg(hMidi,(256*LocSndPar.Voice)+192);
    // convert frequency to midi note
    Note = (int)Round((log(LocSndPar.Freq)-log(440.0))/log(2.0)*12+69,0);
    Phrase = (LocSndPar.Vol*256+Note)*256+144;
    midiOutShortMsg(hMidi,Phrase);
    Sleep((int)(LocSndPar.Dura*(1/LocSndPar.Tempo+0.0001)));
    Phrase = (LocSndPar.Vol*256+Note)*256+128;
    midiOutShortMsg(hMidi,Phrase);
    midiOutClose(hMidi);
    gTexit++;
  }
  CloseHandle(gSThread);
  gSThread = NULL;
  return 0;
}
vegaseat 1,735 DaniWeb's Hypocrite Team Colleague

Replaced Mr. Bloat header iostream with the correct cmath header. This brought the exe file size down from 400k to 19k. Sorry about any discommode!

Tales 0 Light Poster

The code works perfect in DEV C++, but it does not for VC++ (I am running Visual Studio 2005).

bugmenot 25 Posting Whiz in Training

To compile in Visual Studio, add

#pragma comment(lib, "winmm.lib")
t3ch|\/|4n 0 Newbie Poster

This is good code, but I am trying to turn my keyboard into a piano for a fun console app (u dont know how boring cubicles are until u live in one). I do graphics (mostly) and have no experience in sound beyond system bells. Can someone provide some simple musical note code?

Pepperonio 0 Newbie Poster

Thanks for the code, but when I tried to run it (in Dev C++ and Codeblocks) it was having problem with midiOutOpen()

Did I miss something?

marco93 -87 Junior Poster

Use Petzold code instead, 10 x better.

tux4life commented: Use your brain and leave this forum instead of making useless replies, 10x better. -4
yonghc 29 Junior Poster in Training

Dear Vegaseat,

I am interested to hear music or sound from your midi program using Dev-C++. And I did the following as well:

Project>>Project Options>>Parameters>>Add Lib>>libwinmm.a

I created a console application. In Main.cpp, I pasted your whole program. Managed to compile successfully.

When I executed the compiled program, I got a blank screen with a blinking cursor on the top right hand corner, but no sound output.

What could I have done incorrectly?

Regards,

aseire 0 Newbie Poster

thank you vegaseat your snippet up above worked perfectly in my dev c++. I've gone to the "add to reputation" page where I've left you a nod. thanks again. though ... I was wondering about this BCX that was talked about on an other page I looked at. I've been building things in classic vb6 since 1999 now & was curious to know if this BCX could translate its code to compile some working C/C++ apps. otherwise i might have to migrate over to quick basic if BCX might be finicky about what type of basic code it can translate. I've done some audio work with vb6 and have a certain project where I've "installed" a directx 8 reference and built a sound generator. It sounds pretty nice, the blending of the multi-oscillator output is very sweet, plus i have added an additional feature that could render a singular *.wav sound. though with all that could be in C/C++ or vb6 programming, I would seriously love to develop VST synth plugins with C/C++. I suppose that would take some time doing, but in any case thanks so much for your midi tutorial I've learned much from it in the time that I've studied it.

though if i could ask for one small favor possibly ? any chance i could find a snippet to allow a windows frame accompanied with buttons to play separate sounds ? and then possibly a selector where different MIDI fonts could be chosen at runtime ? i'm always trying to enhance what i could learn about audio programming. i've built some fairly decent VST plugins in max/msp. (www.cycling74.com)
max/msp has helped me to learn much of a different type of visual programming. it is a visual OOP environment, though, it does have its drawbacks/shortcomings to a slight extent. please pardon my sounding a bit greedy for information, i wasnt trying to be,... though i would love to know as much as i can about EVERYTHING audio where vb6/C/C++ is concerned. and i thank you ever so much for your showing the snippet.

5/5 stars. Nice concise code. Great comments. Compiled and run on MSVC 6.0 no problem after commenting out

5/5 stars. Nice concise code. Great comments. Compiled and run on MSVC 6.0 no problem after commenting out the using namespace std;

using namespace std;

Metalpeich 0 Newbie Poster

Great solution Vegaseat, I used this code for playing notes by frequency and it was a lot of fun-->

http://latecladeescape.com/recetas-algoritmicas/frecuencia-de-las-notas-musicales.html

moxy 0 Newbie Poster

I get linker errors on devC++
[Linker error] undefined reference to `midiOutOpen@20'
and refs to midiOutShortMsg
and to midiOutClose
What am i missing?

moxy 0 Newbie Poster

I get linker errors on devC++
[Linker error] undefined reference to `midiOutOpen@20'
ditto to midiOutShortMsg
ditto to midiOutClose

What am i missing?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.