- Modes:
- Playback: Emit sound from speaker by writing data to output buffer (in callback).
- Capture: Extract sound from microphone by reading data from input buffer (in callback).
- Sample: Single unit of audio data (when format = f32, a sample is a float in [-1, 1]).
- Frame (PCM Frame): Groups of samples having as many samples as the number of channels (stereo: 1 frame = 2 samples, mono: 1 frame = 1 sample).
- Sample rate: Number of frames processed each second expressed in Hz (e.g 44100 Hz).
- Device: Abstraction for a physical device.
- Callback: Function used to deliver data to/from the device async.
- Data source: Used for retrieving audio data from a source (e.g. decoder, waveform for generrating sine waves...).
- Decoder: Used for reading audio files (wav, mp3, flac).
- Sine wave:
- Amplitude: expresses sound's loudness.
- Frequency: expresses sound's pitch (bass or acute).
Created
April 6, 2024 10:46
-
-
Save h4k1m0u/cf78cd3df706acfe0c2041e0f3aa91e3 to your computer and use it in GitHub Desktop.
Play a sound corresp. to a synthetic note (from sine wave) from soundcard using miniaudio
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Play a sound corresp. to a synthetic note (from sine wave) from soundcard using miniaudio | |
* Modified version of: https://stackoverflow.com/a/72512136/2228912 | |
* How to build: gcc -lm waveform.c -o app | |
* | |
* Other resources: | |
* Raylib sinewave example: https://github.com/raysan5/raylib/blob/master/examples/audio/audio_raw_stream.c | |
* Miniaudio sinewave example: https://github.com/mackron/miniaudio/blob/master/examples/simple_playback_sine.c | |
* Youtube tutorial (sound synth in cpp on windows): https://www.youtube.com/watch?v=tgamhuQnOkM | |
*/ | |
#define MA_NO_DECODING | |
#define MA_NO_ENCODING | |
#define MINIAUDIO_IMPLEMENTATION | |
#include "miniaudio.h" | |
// sample_rate = # of samples / sec => t_sample = 1 / sample_rate | |
const float SAMPLE_RATE = 48000; // for music in movies (44100 for music on CDs) | |
const float DURATION_SAMPLE = 1.0f / SAMPLE_RATE; | |
// A4 note: determines pitch (acute or bass) | |
const float FREQUENCY = 440; | |
float t = 0; | |
/* Populate 'pOutput' with 'frameCount' frames. */ | |
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { | |
// each sample is a float in [-1, 1] | |
float* pOutputF32 = (float*)pOutput; | |
// hakim: frameCount = how many frames can be written to the output buffer | |
// neverending synthetic data generated from sine wave (one iteration fills a single frame) | |
// hakim: sound is represented as a waveform (variation of amplitude as a fct of t) | |
for (ma_uint32 curFrame = 0; curFrame < frameCount; ++curFrame) { | |
// y = f(t) = sin(2pi * freq * t) | |
float y = sin(MA_TAU_D * FREQUENCY * t); | |
// next sample | |
t += DURATION_SAMPLE; | |
// force same sequence (otherwise looping causes a slight change in pitch after a while) | |
if (t >= 1.0) { | |
t = 0; | |
} | |
pOutputF32[curFrame] = y; | |
} | |
// unused | |
(void) pInput; | |
(void) pDevice; | |
} | |
int main(void) { | |
ma_device_config deviceConfig; | |
ma_device device; | |
deviceConfig = ma_device_config_init(ma_device_type_playback); | |
deviceConfig.playback.format = ma_format_f32; | |
deviceConfig.playback.channels = 1; // mono (i.e. 1 frame = 1 sample) | |
deviceConfig.sampleRate = SAMPLE_RATE; | |
deviceConfig.dataCallback = data_callback; | |
if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) { | |
printf("Failed to open playback device.\n"); | |
return 1; | |
} | |
// hakim: begins playback (calls callback) | |
if (ma_device_start(&device) != MA_SUCCESS) { | |
printf("Failed to start playback device.\n"); | |
ma_device_uninit(&device); | |
return 1; | |
} | |
printf("Press Enter to quit...\n"); | |
getchar(); | |
ma_device_uninit(&device); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment