Skip to content

Instantly share code, notes, and snippets.

@tripulse
Created June 11, 2019 12:23
Show Gist options
  • Select an option

  • Save tripulse/0dd6b1bf95a5489ae9c64cb69c7539b1 to your computer and use it in GitHub Desktop.

Select an option

Save tripulse/0dd6b1bf95a5489ae9c64cb69c7539b1 to your computer and use it in GitHub Desktop.
// The MIT License (MIT)
//
// Copyright (c) 2019 vnullptr
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#include <alloca.h>
#include <pulse/pulseaudio.h>
#include <pulse/simple.h>
#define M_PI 3.14159265358979323846
double sign(double x) {
if (x > 0.0) return 1.0;
if (x < 0.0) return -1.0;
return x;
}
// sampling rate: 48kHz, nyquist frequency: 24kHz
#define NB_SAMPLES 48000
static const pa_sample_spec sample_spec = {
.format = PA_SAMPLE_S16LE,
.rate = NB_SAMPLES,
.channels = 1
};
/* Increments based on the sample of the signal. */
float square_wave(
float frequency,
float time
) {
// Equation: "sgn(sin(2πft))"
return sign(sin(2 * M_PI * frequency * time));
}
float sine_wave(
float frequency,
float time
) {
// Equation: "sin(2πft)"
return sin(2 * M_PI * frequency * time);
}
int error_ret;
void abort_(const char * s, ...)
{
va_list args;
va_start(args, s);
vfprintf(stderr, s, args);
fprintf(stderr, "\n");
va_end(args);
abort();
}
int main(int argc, char** argv) {
uint32_t frequency = atoi(argv[1]);
int16_t *sample_buffer;
size_t nb_samples = NB_SAMPLES;
// Allocate the sample buffer to store data.
sample_buffer = alloca(NB_SAMPLES * sizeof(int16_t));
pa_simple *pa_ctx;
pa_usec_t latency;
pa_ctx = pa_simple_new(
NULL,
argv[0],
PA_STREAM_PLAYBACK,
NULL,
"playback",
&sample_spec,
PA_CHANNEL_MAP_DEFAULT,
NULL,
&error_ret
);
/* If the context is failed to allocate. */
if(pa_ctx == NULL)
abort_("Audio context creation is failed: %s", pa_strerror(error_ret));
for(;;) {
latency = pa_simple_get_latency(pa_ctx, NULL);
/* The latency value should not be below zero. */
if(latency < 0)
abort_("Negative latency: %s", pa_strerror(error_ret));
// fill the buffer with square wave
for(size_t s = 0; s < NB_SAMPLES; ++s)
sample_buffer[s] = sine_wave(frequency, (float)s/(float)NB_SAMPLES) * 32767.0;
pa_simple_write(pa_ctx, sample_buffer, NB_SAMPLES*sizeof(int16_t), &error_ret);
/* If the number of bytes written is negative it means that it is falied to write. */
if(error_ret < 0)
abort_("Audio playback is failed: %s", pa_strerror(error_ret));
}
finish:
pa_simple_free(pa_ctx);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment