Page 1 of 1 [ 4 posts ] 

ahayes
Veteran
Veteran

User avatar

Joined: 2 Dec 2006
Gender: Male
Posts: 9,506

21 Apr 2007, 3:14 am

Spawned from the OWA project:
Version .01

play2.h

Code:
#ifndef _PLAY2_H_
#define _PLAY2_H_
#include <iostream>
#include <cmath>
#include <windows.h>

class Play2
{
private:
    int m_nOctave;
    int m_nBPM;
    int m_nBeatSize;
//    int m_nMeasure;
public:
    Play2(int nBPM, int nBeatSize, int nMeasure);
    Play2(int nBPM, int nBeatSize, int nMeasure, int nOctave);
    void PlayNote(int nNote, int nOctave, int nLength);
    void PlayRest(int nLength);
    void SetOctave(int nOctave);
    void SetBPM(int nBPM);
    void SetBeatSize(int nBeatSize);
//    void SetMeasure(int nMeasure);
    int ConvBPM(int nLength);
    friend Play2& operator<<(Play2& play, char *beats);
};

Play2& operator<<(Play2& play, char *beats);

int Log2(int x);

#endif


play2.cpp
Code:
#include "play2.h"
/*
int m_nOctave;
int m_nBPM;
int m_nBeatSize;
int m_nMeasure;
*/

Play2::Play2(int nBPM, int nBeatSize, int nMeasure)
{
    m_nBPM = nBPM;
    m_nBeatSize = nBeatSize;
//    m_nMeasure = nMeasure;
    m_nOctave = 4;
}
Play2::Play2(int nBPM, int nBeatSize, int nMeasure, int nOctave)
{
    m_nBPM = nBPM;
    m_nBeatSize = nBeatSize;
//    m_nMeasure = nMeasure;
    m_nOctave = nOctave;
}

//freq=440*2^((-9+a)/12+n-4)

void Play2::PlayNote(int nNote, int nOctave, int nLength)
{
    double pitch = 440.0*pow(2.0, ((double)nNote-9.0)/12.0+(double)nOctave-4.0);
    Beep((int)pitch, ConvBPM(nLength));
}
void Play2::PlayRest(int nLength)
{
    Beep(0x7FFF, ConvBPM(nLength));
}

int Play2::ConvBPM(int nLength)
{
    double time = (double)m_nBPM;
    time = 1/time;
    time *=60;
    time *=1000;
    time *= pow(2.0, (double)Log2(m_nBeatSize)-Log2(nLength));
    return (int)time;
}

Play2& operator<<(Play2& play, char *beats)
{
    //types of notes
    const int CNOTE=0, CSHARP=1, DFLAT=1, DNOTE=2, DSHARP=3, EFLAT=3, ENOTE=4,
        FNOTE=5, FSHARP=6, GFLAT=6, GNOTE=7, GSHARP=8, AFLAT=8, ANOTE=9,
        ASHARP=10, BFLAT=10, BNOTE=11;
    //initial beat length = 4
    int beatLength = 4;
    //run through stream
    int i = 0;
    while(beats[i] != 0 && beats[i+1] != 0)
    {
        bool flat = false;
        bool sharp = false;
        //find sharp and flat notes
        switch(beats[i+1])
        {
            case '&':
                flat = true;
                break;
            case '#':
                sharp = true;
                break;
            default:
                break;
        }
        //find notes, octave changes, rests, beat length changes
        switch(beats[i])
        {
            case 'c':
                if(sharp)
                    play.PlayNote(CSHARP, play.m_nOctave, beatLength);
                else
                    play.PlayNote(CNOTE, play.m_nOctave, beatLength);
                break;
            case 'd':
                if(flat)
                    play.PlayNote(DFLAT, play.m_nOctave, beatLength);
                else if(sharp)
                    play.PlayNote(DSHARP, play.m_nOctave, beatLength);
                else
                    play.PlayNote(DNOTE, play.m_nOctave, beatLength);
                break;
            case 'e':
                if(flat)
                    play.PlayNote(EFLAT, play.m_nOctave, beatLength);
                else
                    play.PlayNote(ENOTE, play.m_nOctave, beatLength);
                break;
            case 'f':
                if(sharp)
                    play.PlayNote(FSHARP, play.m_nOctave, beatLength);
                else
                    play.PlayNote(FNOTE, play.m_nOctave, beatLength);
                break;
            case 'g':
                if(sharp)
                    play.PlayNote(GSHARP, play.m_nOctave, beatLength);
                else if(flat)
                    play.PlayNote(GFLAT, play.m_nOctave, beatLength);
                else
                    play.PlayNote(GNOTE, play.m_nOctave, beatLength);
                break;
            case 'a':
                if(sharp)
                    play.PlayNote(ASHARP, play.m_nOctave, beatLength);
                else if(flat)
                    play.PlayNote(AFLAT, play.m_nOctave, beatLength);
                else
                    play.PlayNote(ANOTE, play.m_nOctave, beatLength);
                break;
            case 'b':
                if(flat)
                    play.PlayNote(BFLAT, play.m_nOctave, beatLength);
                else
                    play.PlayNote(BNOTE, play.m_nOctave, beatLength);
                break;
            case 'C':
                if(sharp)
                    play.PlayNote(CSHARP, play.m_nOctave+1, beatLength);
                else
                    play.PlayNote(CNOTE, play.m_nOctave+1, beatLength);
                break;
            case 'D':
                if(flat)
                    play.PlayNote(DFLAT, play.m_nOctave+1, beatLength);
                else if(sharp)
                    play.PlayNote(DSHARP, play.m_nOctave+1, beatLength);
                else
                    play.PlayNote(DNOTE, play.m_nOctave+1, beatLength);
                break;
            case 'E':
                if(flat)
                    play.PlayNote(EFLAT, play.m_nOctave+1, beatLength);
                else
                    play.PlayNote(ENOTE, play.m_nOctave+1, beatLength);
                break;
            case 'F':
                if(sharp)
                    play.PlayNote(FSHARP, play.m_nOctave+1, beatLength);
                else
                    play.PlayNote(FNOTE, play.m_nOctave+1, beatLength);
                break;
            case 'G':
                if(sharp)
                    play.PlayNote(GSHARP, play.m_nOctave+1, beatLength);
                else if(flat)
                    play.PlayNote(GFLAT, play.m_nOctave+1, beatLength);
                else
                    play.PlayNote(GNOTE, play.m_nOctave+1, beatLength);
                break;
            case 'A':
                if(sharp)
                    play.PlayNote(ASHARP, play.m_nOctave+1, beatLength);
                else if(flat)
                    play.PlayNote(AFLAT, play.m_nOctave+1, beatLength);
                else
                    play.PlayNote(ANOTE, play.m_nOctave+1, beatLength);
                break;
            case 'B':
                if(flat)
                    play.PlayNote(BFLAT, play.m_nOctave+1, beatLength);
                else
                    play.PlayNote(BNOTE, play.m_nOctave+1, beatLength);
                break;
            case '1':
                beatLength = 1;
                break;
            case '2':
                beatLength = 2;
                break;
            case '4':
                beatLength = 4;
                break;
            case '8':
                beatLength = 8;
                break;
            case '6':
                beatLength = 16;
                break;
            case '3':
                beatLength = 32;
                break;
            case '+':
                play.m_nOctave++;
                break;
            case '-':
                play.m_nOctave--;
                break;
            case ';':
                play.PlayRest(beatLength);
                break;
            default:
                break;
        }
        i++;
    }
    return play;
}

int Log2(int x)
{
    return (int)(log((double)x)/log(2.0));
}


This code works with MinGW.

edit:

I have added code to play back music put in files:
play2pl2.h
Code:
#ifndef _PLAY2PL2_H_
#define _PLAY2PL2_H_

#include <iostream>
#include <fstream>
#include "play2.h"

using std::ifstream;
using std::cout;
using std::endl;

class Pl2File
{
private:
   Play2 *play2;
   ifstream infile;
   char *filename;
public:
   Pl2File(Pl2File const &pl2);
   Pl2File(char filename[]);
   Pl2File();
   ~Pl2File();
   void play();
   void load(char filename[]);
};

#endif


play2pl2.cpp
Code:
#include "play2pl2.h"

Pl2File::Pl2File(Pl2File const &pl2)
{
   if(pl2.play2)
   {
      this->load(pl2.filename);
   }
   else
      this->play2=0;
}

Pl2File::Pl2File(char filename[])
{
   this->filename=filename;
   infile.open(filename);
   int nBPM;
   int nBeatSize;
   int nMeasure;
   int nOctave;
   infile >> nBPM;
   infile >> nBeatSize;
   infile >> nMeasure;
   infile >> nOctave;
   while(1)//get past comments
   {
      char inputs[1000];
      infile >> inputs;
      if(!infile)
      {
         cout << "Incorrectly Formatted File" << endl;
         cout << "Program Aborted" << endl;
         system("pause");
         this->infile.close();
         delete this->play2;
         exit(1);
      }
      if(inputs[0]!=0)
      {
         if(inputs[0] == '*' && inputs[1]=='/')
         {
            break;
         }
      }
   }
   this->play2=new Play2(nBPM, nBeatSize, nMeasure, nOctave);
}

Pl2File::Pl2File()
{
   this->play2=0;
}

Pl2File::~Pl2File()
{
   if(this->play2!=0)
      delete this->play2;
   this->infile.close();
}
void Pl2File::play()
{
   if(!this->play2)
      return;
   char inputs[1000];
   while(this->infile)
   {
      this->infile >> inputs;
      if(inputs[0]=='*')
      {
         switch(inputs[1])
         {
         case 'b':
            int nBPM;
            this->infile>>nBPM;
            this->play2->SetBPM(nBPM);
            break;
         case 's':
            int nBeatSize;
            this->infile>>nBeatSize;
            this->play2->SetBeatSize(nBeatSize);
            break;
         case 'm':
            /*
            int nMeasure;
            this->infile>>nMeasure;
            this->play2->SetMeasure(nMeasure);
            */
            break;
         case 'o':
            int nOctave;
            this->infile>>nOctave;
            this->play2->SetOctave(nOctave);
            break;
         default:
            break;
         }
      }
      else
         *this->play2 << inputs;
   }
}
void Pl2File::load(char filename[])
{
   this->filename=filename;
   if(this->play2)
   {
      delete this->play2;
      this->infile.close();
   }
   infile.open(filename);
   int nBPM;
   int nBeatSize;
   int nMeasure;
   int nOctave;
   infile >> nBPM;
   infile >> nBeatSize;
   infile >> nMeasure;
   infile >> nOctave;
   while(1)//get past comments
   {
      char inputs[1000];
      infile >> inputs;
      if(!infile)
      {
         cout << "Incorrectly Formatted File" << endl;
         cout << "Program Aborted";
         throw;
      }
      if(inputs[0] == '*' && inputs[1]=='/')
      {
         break;
      }
   }
   this->play2=new Play2(nBPM, nBeatSize, nMeasure, nOctave);
}


This demonstrates how to use Pl2File in a program that takes the filename as a parameter
and playes it.

main.ccp
Code:
#include "play2pl2.h"
#include <iostream>
#include <fstream>

using std::cout;
using std::endl;
using std::ifstream;

int main(int argc, char* argv[])
{
   if(argc !=2)
   //if(false)
   {
      cout << "Invalid Parameters" << endl;
      system("pause");
      return 1;
   }
   else
   {
      Pl2File pl2(argv[1]);
      //Pl2File pl2("C:\\Temp\\play2\\Debug\\twinklw.pl2");
      pl2.play();
   }
   return 0;
}


Here is the specs I wrote up for pl2 files
Code:
-----------------
pl2 specification
-----------------

At the begining of the file there MUST be the following:

Beats per minute
Length of beats (1 for whole, 2 for half, 4 for quarter, 8 for eighth, 16 for sixteenth, 32 for 32nd)
# of beats in measure
Octave (1 for C1, 2 for C2, 3 for C3, 4 for C4...)

then any comments you may wish to add to the file

these characters after a new line: */

the notes you wish to play OR an escape sequence to change the following:

*b followed by a space and the desired beats per minute
*s followed by a space and the desired beat size
*m followed by a space and the desired # of beats in a measure
*o followed by a space and the desired octave

the notes follow the following format:

the note 'c', 'd', 'e', 'f', 'g', 'a', 'b'
symbold for flat or sharp notes: '&' for flat, '#' for sharp
if a note is capitalized it will play one octave up from the current octave

inline with the notes the following can be used to change octaves or note sizes

1 for whole note, 2 for half note, 4 for quarter note, 8 for eighth note, 6 for sixteenth note, 3 for 32nd note

'+' to go up one octave

'-' to go down one octave

changes in note size will only affect the following notes on the line
changes in octave will be in effect for the point of the octave change on

a rest is entered with a semicolon ';'

any spaces or line breaks must be terminated with a comma ',' or the character of the line will be ignored

the default note is a quarter note, notes of other sizes must be specified every line/seperation

here is an example .pl2 file:

135 4 4 4
/* <-reccommended to begin comments
anything on these lines will be ignored
cdefgab
\/-the characters on this line will end the comments.  no comments may be entered after this
*/

ccggaag;,
ffeeddc;,
ffeeddc;,
ffeeddc;,
ccggaag;,
ffeeddc;,
;;;;,
3ffeeddc;, ffeeddc,
2+ffeeddc;,

*b 200

-ffeeddc;,
-end of file (do not include this line in the file)-

this file will start out with 134 beats per minute, a beat will be a quarter note
there will be four per measure and will start out with the octave C4

it will them play ccggaag in quarter notes followed by a quarter rest
it will them play ffeeddc in quarter notes followed by a quarter rest
it will them play ffeeddc in quarter notes followed by a quarter rest
it will them play ffeeddc in quarter notes followed by a quarter rest
it will them play ccggaag in quarter notes followed by a quarter rest
it will them play ffeeddc in quarter notes followed by a quarter rest
it will play four rests
it will then play ffeeddc in 32nd notes followed by a 32nd rest
after the space it will go back to the default quarter notes and play ffeeddc
it will then play ffeeddc in half notes one octave up C4 (C5)

the number of beats per minute will change to 200 as per the escape sequence

it will go down one octave back to C4 and play ffeeddc in quarter notes followed by
a quarter rest



Last edited by ahayes on 22 Apr 2007, 6:57 pm, edited 1 time in total.

ahayes
Veteran
Veteran

User avatar

Joined: 2 Dec 2006
Gender: Male
Posts: 9,506

21 Apr 2007, 3:20 am

http://www.mediafire.com/?emkkd0bz2dm

A small program for testing.

main.cpp used for this program

Code:
#include <cstdlib>
#include <iostream>
#include "play2.h"

using namespace std;

int main(int argc, char *argv[])
{
    Play2 *play = new Play2(135, 4, 4, 4);
    char *chars = new char[50];
    label1:
    cout << "Enter notes: ";
    cin >> chars;
    *play << chars;
    cout << "Again?(y/n)";
    cin >> chars;
    if(chars[0]=='y')
        goto label1;
    system("PAUSE");
    return EXIT_SUCCESS;
}



ahayes
Veteran
Veteran

User avatar

Joined: 2 Dec 2006
Gender: Male
Posts: 9,506

22 Apr 2007, 7:13 pm

Update: Added code and specification for playing from external .pl2 files. Also added program to play a specified file.

Here's a linky PlayPl2.zip



ahayes
Veteran
Veteran

User avatar

Joined: 2 Dec 2006
Gender: Male
Posts: 9,506

23 Apr 2007, 12:24 pm

plank.pl2

Code:
130 4 4 3
/*
Only a Plank Between One and Perdition
*/

D;1;, 1;, 8gdgdgfed,
8gbagfeg-b+, 8++abaCbgab, 8aCbgabab,
8abaCbgab, 8aCbgabab, 8abaCbgab,

8aCbgabab, 8abaCbgab, 8aCbgabab,
8abaCbgab, 8aCbCabab, 8abaCbCab,
8aCbgabab, 8abaCbgab, 8aCbgabab,
8abaCbgab, 8aCbgabab, 8abaCbgab,
8aCbgabab, 8abaCbgab, 8aCbgabab,

*m 3

--4;2B, 2B, 4;2A, 2A,
4;2A, 2A, 4;2G, 2G,
8++cdcdgd-g+, 8cdcdgd-g+, 8cdcdgd-g+, 8cdcdgd-g+,
8cdcdgd-g+, 8cdcdgd-g+, 8cdcdgd-g+,
8cdcge-g+, 8cdcdcd, 8cgd-g+cdcd,


Hmm, should probably find a better tune.