Start with the startA.cpp file for this part. You CANNOT change main() from how
ID: 3822331 • Letter: S
Question
Start with the startA.cpp file for this part. You
CANNOT
change main() from how it is currently
written. Instead, you need to add to the “Beeper” class to make main() work and play sound. You
should first be able to enter the “beats-per-minute” of the song. Thus 60 bpm is 1 note a second and
120 bpm is 2 notes a second. Computers typically calculate time in milliseconds (1 / 1,000
th
of a
second) so you will have to convert units. Next the user will input notes (in upper case), which you
should play at the bpm entered (the playing should happen on the “cin >> b;” line of code).
To play notes, you will need to specify the pitch in Hertz (Hz) of the notes. You can reference this
webpage:
http://www.phy.mtu.edu/~suits/NoteFreqCalcs.html
For those of you unfamiliar with music, there are seven notes:
C D E F G A B
The link above says to start the “A” note at 440 Hz (please choose this definition). Then they give you
a formula based on the number of half-steps. These are:
A -> B = 2 half-steps
A -> A = 0 half-steps
A -> G = -2 half-steps
A -> F = -4 half-steps
A -> E = -5 half-steps
A -> D = -7 half-steps
A -> C = -9 half-steps
(Hint: you should look around the “SDLaudioPlayer.cpp” example to figure out how to play sound.)
In addition to reading notes, your program should also read periods (“.”) as rests (no sound). To do
this, simply put a very low frequency Hz (outside of the hearing range).
Example 1 (user input underlined, desired sound posted on website):
Enter tempo (bpm)
60
Enter song
CEG.GEC
StartA.cpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>
#include <queue>
#include <cmath>
#include <iostream>
using namespace std;
/** Consts used for standard audio playback **/
const int AMPLITUDE = 28000*2;
const int FREQUENCY = 44100;
const int DURATION = 250;
class Beeper;
/** FUNCTIONS THAT ARE DONE **/
void audio_callback(void*, Uint8*, int);
/** Helper struct used to generate samples **/
struct BeepObject
{
double freq;
int samplesLeft;
};
/** You will need to add to this class
** Code given can be played interactively
**/
class Beeper
{
private:
double v;
queue<BeepObject> beeps;
public:
Beeper();
~Beeper();
void beep(double, int);
void generateSamples(Sint16 *stream, int length);
void wait();
};
int main() // YOU CANNOT CHANGE MAIN!
{
SDL_Init(SDL_INIT_AUDIO);
Beeper b;
cout << "Enter tempo (bpm)" << endl;
int bpm;
cin >> bpm;
b.setTempo(bpm); // Make this!
cout << "Enter song" << endl;
cin >> b; // this line should play the song
b.wait(); // ensures song finishes playing before program stops
return 0;
}
/** SHOULD NOT NEED TO TOUCH ANYTHING BELOW HERE **/
/** USE IT TO LEARN BUT NO CHANGES NEED TO BE MADE **/
void audio_callback(void *_beeper, Uint8 *_stream, int _length)
{
Sint16 *stream = (Sint16*) _stream;
int length = _length / 2;
Beeper* beeper = (Beeper*) _beeper;
beeper->generateSamples(stream, length);
}
Beeper::Beeper()
{
SDL_AudioSpec desiredSpec;
desiredSpec.freq = FREQUENCY;
desiredSpec.format = AUDIO_S16SYS;
desiredSpec.channels = 1;
desiredSpec.samples = 2048;
desiredSpec.callback = audio_callback;
desiredSpec.userdata = this;
SDL_AudioSpec obtainedSpec;
SDL_OpenAudio(&desiredSpec, &obtainedSpec);
// start play audio
SDL_PauseAudio(0);
}
Beeper::~Beeper()
{
SDL_CloseAudio();
}
void Beeper::generateSamples(Sint16 *stream, int length)
{
int i = 0;
while (i < length) {
if (beeps.empty()) {
while (i < length) {
stream[i] = 0;
i++;
}
return;
}
BeepObject& bo = beeps.front();
int samplesToDo = min(i + bo.samplesLeft, length);
bo.samplesLeft -= samplesToDo - i;
while (i < samplesToDo) {
stream[i] = AMPLITUDE * sin(v * 2 * M_PI / FREQUENCY);
i++;
v += bo.freq;
}
if (bo.samplesLeft == 0) {
beeps.pop();
}
}
}
void Beeper::beep(double freq, int duration)
{
BeepObject bo;
bo.freq = freq;
bo.samplesLeft = duration * FREQUENCY / 1000;
SDL_LockAudio();
beeps.push(bo);
SDL_UnlockAudio();
}
void Beeper::wait()
{
int size;
do {
SDL_Delay(20);
SDL_LockAudio();
size = beeps.size();
SDL_UnlockAudio();
} while (size > 0);
}
Explanation / Answer
#include #include #include #include const int AMPLITUDE = 28000; const int FREQUENCY = 44100; struct BeepObject { double freq; int samplesLeft; }; class Beeper { private: double v; std::queue beeps; public: Beeper(); ~Beeper(); void beep(double freq, int duration); void generateSamples(Sint16 *stream, int length); void wait(); }; void audio_callback(void*, Uint8*, int); Beeper::Beeper() { SDL_AudioSpec desiredSpec; desiredSpec.freq = FREQUENCY; desiredSpec.format = AUDIO_S16SYS; desiredSpec.channels = 1; desiredSpec.samples = 2048; desiredSpec.callback = audio_callback; desiredSpec.userdata = this; SDL_AudioSpec obtainedSpec; // you might want to look for errors here SDL_OpenAudio(&desiredSpec, &obtainedSpec); // start play audio SDL_PauseAudio(0); } Beeper::~Beeper() { SDL_CloseAudio(); } void Beeper::generateSamples(Sint16 *stream, int length) { int i = 0; while (iRelated Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.