I've started to play with PortAudio library about week ago. I've checked most of tutorial/test examples but haven't seen solution for what I need. I'm making simple sequencer - I've already done drawing sounds as blocks on the piano roll, but now I need make it sound somehow. I wonder if there is possibility to get it working like this:
In example files it looks more complicated. When I want to play multiple sine waves, so I have to merge all that waves, and then give that data to stream.
Maybe someone got better solutions to resolve this problem?
I'll just give you a simple example (for a sine wave
) and then you can create other types of waves you're interested in. The input parameters needed are
- sampling rate (e.g 8000, 16000 etc)
- amplitude (the actual values depend on the output format but it's best to have values in the range 0-1 and convert them to whatever format you like/need)
- frequency (expressed as a fraction of the sampling rate)
- duration (in seconds)
The buffer length for tone data (samples) is determined by the tone duration
in seconds multiplied by the sampling rate
.
The actual code to create a sine wave may look something like the following
//global variables
const float PI = 3.141593;
const unsigned samplingRate = 8000;
const float amp = 0.8;
float *GenerateTone(float frequency, unsigned duration, unsigned &bufferLen){
const float freq = frequency/samplingRate; //(e.g 440 / 8000 = 0,055)
bufferLen = samplingRate * duration;
float *buffer = new float[bufferLen]
for(int i = 0; i < bufferLen; i++ ){
buffer[i] = amp * sin(2 * PI*freq * ((float)i)/samplingRate);
}
return buffer;
}
You can call this function like
unsigned len;
float *pTone = GenerateTone(440, 1, len);//len is an out parameter
...
delete [] pTone; //deallocatone memory when you no longer need it
In C++, you can also use std::vector
to store the samples. This way you don't have to worry about memory allocation/deallocation.
std::vector<float> v; //make vector global
const float PI = 3.141593;
const unsigned samplingRate = 8000;
const float amp = 0.8;
void GenerateTone(float frequency, unsigned duration){
const amp = 0.8f;
const float freq = frequency/samplingRate;
const unsigned len = samplingRate * duration;
for(int i = 0; i < len; i++ )
v.push_back(amp * sin(2*PI*freq * ((float)i)/sampleRate));
}
You can also pass amplitude as a paramater but in the examples above the amplitude is hardcoded. Also, see (https://en.wikipedia.org/wiki/Triangle_wave, https://en.wikipedia.org/wiki/Square_wave )