Raspberry Pi generate tone with PiFM - c++

While back I came across PiFM and decided to learn a bit about audio and modulation. I am trying to write an AFSK modulator, but first I wanted to generate pure tones, like 1000Hz. I am using code from the PiFM project (https://github.com/rm-hull/pifm/blob/master/pifm.cpp) which reads in a WAV file and shoots it out over RF. I want to do the same but I want to shoot out pure tones over RF.
Here is one of my attempts:
void playSineWave(float frequency, int duration, float samplerate)
{
SampleSink* ss;
ss = new Outputter(samplerate);
int bufferLen = duration * samplerate;
float* buffer = new float[bufferLen];
for (int i = 0; i < bufferLen; i++) {
float amplitude = 6000;
buffer[i] = amplitude * sin( (2.f * float(M_PI) * i * frequency) / samplerate );
}
cout << "Buffer length: " << bufferLen << endl;
ss->consume(buffer, bufferLen);
delete [] buffer;
}
I would use it as such playSineWave(1000, 5, 22050); to play 1000Hz tone for 5 seconds. But I get either nothing or noise. Can you guys suggest how to fix it or perhaps some good reading material?
Edit: Changed code to fix issue with amplitude. Still no tone.

I'm not sure if it's intentional to make amplitude change over time. Anyhow, i / bufferLen * 32760 is evaluated as (i / bufferLen) * 32760 and i / bufferLen is going to be 0 for all i smaller than bufferLen (look up integer division in C/C++), which is the case because of for (int i = 0; i < bufferLen; i++).

Related

Static noise in generated sine wave pcm sound

This is very similar to a question here but I don't seem to be able to apply the solution.
I have a code that samples a sine wave and writes it into a pcm file. When I listen to it with ffplay, there is some static noise that I don't know where it comes from. Based on the solution in the mentioned post, I use a binary file for writting out and I make sure I play the file with signed 8 bit format.
This is the code I use:
int createSineWavePCM(int freq, int sample_rate) {
char out_name[100];
sprintf(out_name, "../sine_freq%d_sr%d.pcm", freq, sample_rate);
ofstream outfile(out_name, ios::binary);
char data[1000000];
for (int j = 0 ; j < 1000000 ; ++j) {
double ll = 50.0L * sin((2.0L * M_PIl * j * freq / sample_rate));
data[j] = ll;
}
outfile.write(data, sizeof data);
outfile.close();
cout << "Stored sine wave pcm file in " << out_name << endl;
return 0;
}
I use freq = 440 and sample_rate = 44100, and then I play with:
ffplay {pcm_file} -f s8 -sample_rate 44100
Any ideas on what may cause the static noise?
The expression in the sin function looks dubious. Are all the components of type int or long? You wrote 2.0L, and I'm surprised that parses, but L usually converts a number to a long. Also it seems like M_PI has an l appended which would possibly also make that a long. If this is the case, the division being performed freq / sample_rate could well be integer division.

Detecting linear interpolation of two frequnecies on embedded system

I am trying to recognise a sequence of audio frames on an embedded system - an audio frame being a frequency or interpolation of two frequencies for a variable amount of time. I know the sounds I am trying to recognise (i.e. the start and end frequencies which are being linearly interpolated and the duration of each audio frame), but they are produced by a another embedded system so the microphone and speaker are cheap and somewhat inaccurate. The output is a square wave. Any suggestions how to go about doing this?
What I am trying to do now is to use FFT to get the magnitude of all frequencies, detect the peaks, look at the detection duration/2 ms ago and check if that somewhat matches an audio frame, and finally just checking if any sound I am looking for matched the sequence.
So far I used the FFT to process the microphone input - after applying a Hann window - and then assigning each frequency bin a coefficient that it's a peak based on how many standard deviations is away from the mean. This hasn't worked great since it thought there are peaks when it was silence in the room. Any ideas on how to more accurately detect the peaks? Also I think there are a lot of harmonics because of the square wave / interpolation? Can I do harmonic product spectrum if the peaks don't really line up at double the frequency?
Here I graphed noise (almost silent room) with somewhere in the interpolation of 2226 and 1624 Hz.
https://i.stack.imgur.com/R5Gs2.png
I sample at 91 microseconds -> 10989 Hz. Should I sample more often?
I added here samples of how the interpolation sounds when recorded on my laptop and on the embedded system.
https://easyupload.io/m/5l72b0
#define MIC_SAMPLE_RATE 10989 // Hz
#define AUDIO_SAMPLES_NUMBER 1024
MicroBitAudioProcessor::MicroBitAudioProcessor(DataSource& source) : audiostream(source)
{
arm_rfft_fast_init_f32(&fft_instance, AUDIO_SAMPLES_NUMBER);
buf = (float *)malloc(sizeof(float) * (AUDIO_SAMPLES_NUMBER * 2));
output = (float *)malloc(sizeof(float) * AUDIO_SAMPLES_NUMBER);
mag = (float *)malloc(sizeof(float) * AUDIO_SAMPLES_NUMBER / 2);
}
float henn(int i){
return 0.5 * (1 - arm_cos_f32(2 * 3.14159265 * i / AUDIO_SAMPLES_NUMBER));
}
int MicroBitAudioProcessor::pullRequest()
{
int s;
int result;
auto mic_samples = audiostream.pull();
if (!recording)
return DEVICE_OK;
int8_t *data = (int8_t *) &mic_samples[0];
int samples = mic_samples.length() / 2;
for (int i=0; i < samples; i++)
{
s = (int) *data;
result = s;
data++;
buf[(position++)] = (float)result;
if (position % AUDIO_SAMPLES_NUMBER == 0)
{
position = 0;
float maxValue = 0;
uint32_t index = 0;
// Apply a Henn window
for(int i=0; i< AUDIO_SAMPLES_NUMBER; i++)
buf[i] *= henn(i);
arm_rfft_fast_f32(&fft_instance, buf, output, 0);
arm_cmplx_mag_f32(output, mag, AUDIO_SAMPLES_NUMBER / 2);
}
}
return DEVICE_OK;
}
uint32_t frequencyToIndex(int freq) {
return (freq / ((uint32_t)MIC_SAMPLE_RATE / AUDIO_SAMPLES_NUMBER));
}
float MicroBitAudioProcessor::getFrequencyIntensity(int freq){
uint32_t index = frequencyToIndex(freq);
if (index <= 0 || index >= (AUDIO_SAMPLES_NUMBER / 2) - 1) return 0;
return mag[index];
}

FFT Spectrum not displaying correctly

I'm currently trying to display an audio spectrum using FFTW3 and SFML. I've followed the directions found here and looked at numerous references on FFT and spectrums and FFTW yet somehow my bars are almost all aligned to the left like below. Another issue I'm having is I can't find information on what the scale of the FFT output is. Currently I'm dividing it by 64 yet it still reaches beyond that occasionally. And further still I have found no information on why the output of the from FFTW has to be the same size as the input. So my questions are:
Why is the majority of my spectrum aligned to the left unlike the image below mine?
Why isn't the output between 0.0 and 1.0?
Why is the input sample count related to the fft output count?
What I get:
What I'm looking for:
const int bufferSize = 256 * 8;
void init() {
sampleCount = (int)buffer.getSampleCount();
channelCount = (int)buffer.getChannelCount();
for (int i = 0; i < bufferSize; i++) {
window.push_back(0.54f - 0.46f * cos(2.0f * GMath::PI * (float)i / (float)bufferSize));
}
plan = fftwf_plan_dft_1d(bufferSize, signal, results, FFTW_FORWARD, FFTW_ESTIMATE);
}
void update() {
int mark = (int)(sound.getPlayingOffset().asSeconds() * sampleRate);
for (int i = 0; i < bufferSize; i++) {
float s = 0.0f;
if (i + mark < sampleCount) {
s = (float)buffer.getSamples()[(i + mark) * channelCount] / (float)SHRT_MAX * window[i];
}
signal[i][0] = s;
signal[i][1] = 0.0f;
}
}
void draw() {
int inc = bufferSize / 2 / size.x;
int y = size.y - 1;
int max = size.y;
for (int i = 0; i < size.x; i ++) {
float total = 0.0f;
for (int j = 0; j < inc; j++) {
int index = i * inc + j;
total += std::sqrt(results[index][0] * results[index][0] + results[index][1] * results[index][1]);
}
total /= (float)(inc * 64);
Rectangle2I rect = Rectangle2I(i, y, 1, -(int)(total * max)).absRect();
g->setPixel(rect, Pixel(254, toColor(BLACK, GREEN)));
}
}
All of your questions are related to the FFT theory. Study the properties of FFT from any standard text/reference book and you will be able to answer your questions all by yourself only.
The least you can start from is here:
https://en.wikipedia.org/wiki/Fast_Fourier_transform.
Many FFT implementations are energy preserving. That means the scale of the output is linearly related to the scale and/or size of the input.
An FFT is a DFT is a square matrix transform. So the number of outputs will always be equal to the number of inputs (or half that by ignoring the redundant complex conjugate half given strictly real input), unless some outputs are thrown away. If not, it's not an FFT. If you want less outputs, there are ways to downsample the FFT output or post process it in other ways.

fftw slight peak inaccuracy/drifting

I am using fftw to get spectrum of an Audio Signal. I get Audio Samples in float32 and have also tried other formats using PortAudio. Then I take fft of it using fftw. In all the formats, I have slight drift of frequency peak from actual frequency. My setup is.
Signal Generator to supply sinusoidal signal.
Sampling rate of 44.1KHz.
I am getting correct/relatively accurate readings till 10KHz. However as I gradually increase the frequency of Generator, I start getting offset. For example above 10KHz, this is what happens.
Actual frequency Peak on Spectrum
10KHz 10.5KHz
12KHz 12.9KHz
14KHz 15.5KHz
16KHz 18.2KHz
The fft Code is as like this.
//Take Samples and do Windowing
for( i=0; i<framesPerBuffer; i++ )
{
samples[i] = in[i];
fft->fftIn[i] = (0.54-(0.46*cos(scale_fact*i))) * samples[i];
}
//Zero Padding
for(i=framesPerBuffer; i<fftSize; i++)
{
fft->fftIn[i] = 0.0;
}
//FFTW Code
{ fftSize = fftSize;
this->fftSize = fftSize;
cout << "Plan start " << endl;
outArraySize = fftSize/2+1;
cout << "fft Processor start \n";
fftIn = ((double*) fftw_malloc(sizeof(double) * fftSize));
fftOut = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * outArraySize );
fftOutAbs = (double*) fftw_malloc(sizeof(double) * outArraySize );
fftwPlan = fftw_plan_dft_r2c_1d(fftSize, fftIn, fftOut, FFTW_ESTIMATE);
// fftwPlan = fftw_plan_dft_r2c_1d(fftSize, fftIn, fftOut, FFTW_MEASURE);
}
//Absolute response
int n=fftSize/2+1;
for(int i=0; i < n; i++)
{
fftOutAbs[i] = sqrt(fftOut[i][0]*fftOut[i][0] + fftOut[i][1]*fftOut[i][1]);
}
for(unsigned int i=0; i < n; i++)
{
mainCureYData[i] = 20.0 * log10(one_over_n * fft->fftOutAbs[i]);
}
I need some hints as to where/why this problem could be ?
The Hardware setup look fine as the peak shows correct on sndpeek application.
Thanks,
You don't actually show the code where you calculate the frequency of the peak, but my guess is that the problem is here:
int n=fftSize/2+1;
This should most likely be:
int n=fftSize/2;
See this answer and/or this answer for an explanation of how to determine frequency from FFT output. (TL;DR: f = Fs * i / n)

Explanation of a this Vst Synth example

I am having trouble understanding a particular area of code in the Steinberg VST Synth example
In this function:
void VstXSynth::processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames)
{
float* out1 = outputs[0];
float* out2 = outputs[1];
if (noteIsOn)
{
float baseFreq = freqtab[currentNote & 0x7f] * fScaler;
float freq1 = baseFreq + fFreq1; // not really linear...
float freq2 = baseFreq + fFreq2;
float* wave1 = (fWaveform1 < .5) ? sawtooth : pulse;
float* wave2 = (fWaveform2 < .5) ? sawtooth : pulse;
float wsf = (float)kWaveSize;
float vol = (float)(fVolume * (double)currentVelocity * midiScaler);
VstInt32 mask = kWaveSize - 1;
if (currentDelta > 0)
{
if (currentDelta >= sampleFrames) // future
{
currentDelta -= sampleFrames;
return;
}
memset (out1, 0, currentDelta * sizeof (float));
memset (out2, 0, currentDelta * sizeof (float));
out1 += currentDelta;
out2 += currentDelta;
sampleFrames -= currentDelta;
currentDelta = 0;
}
// loop
while (--sampleFrames >= 0)
{
// this is all very raw, there is no means of interpolation,
// and we will certainly get aliasing due to non-bandlimited
// waveforms. don't use this for serious projects...
(*out1++) = wave1[(VstInt32)fPhase1 & mask] * fVolume1 * vol;
(*out2++) = wave2[(VstInt32)fPhase2 & mask] * fVolume2 * vol;
fPhase1 += freq1;
fPhase2 += freq2;
}
}
else
{
memset (out1, 0, sampleFrames * sizeof (float));
memset (out2, 0, sampleFrames * sizeof (float));
}
}
The way I understand the function is that if a midi note is currently on, we need to copy our wave table into the outputs array to pass back to the VstHost. What I don't understand specifically is what the area in the if (currentDelta > 0) conditional block is doing. It seems like its just writing zeros to the output arrays...
A full version of the file can be found at http://pastebin.com/SdAXkRyW
The incomming MIDI NoteOn event can have an offset relative to the start of the buffers you receive (called deltaFrames). The currentDelta keeps track of when the note should play relative to the start of the buffers received.
So if the currentDelta > sampleFrames, that means the note should not play in this cycle (future) - early exit.
If the currentDelta is within range of this cycle then the memory is cleared up to the moment the note should produce output (memset) and the pointers are manipulated to make it look like the buffers begin right on the spot where the sound should play - length -sampleFrames- is also adjusted.
Then in the loop the sound is produced.
Hope it helps.
Marc