mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
133 lines
4 KiB
C
133 lines
4 KiB
C
#if 0
|
|
/*─────────────────────────────────────────────────────────────────╗
|
|
│ To the extent possible under law, Justine Tunney has waived │
|
|
│ all copyright and related or neighboring rights to this file, │
|
|
│ as it is written in the following disclaimers: │
|
|
│ • http://unlicense.org/ │
|
|
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
|
╚─────────────────────────────────────────────────────────────────*/
|
|
#endif
|
|
#include <cosmoaudio.h>
|
|
#include <math.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
|
|
/**
|
|
* @fileoverview prints ascii meter of microphone loudness
|
|
*
|
|
* 0. -60 dB is nearly silent, barely audible, even in a quiet room
|
|
* 1. -50 dB is very quiet background sounds
|
|
* 2. -40 dB is quiet ambient noise
|
|
* 3. -30 dB is clear but soft sounds
|
|
* 4. -20 dB is moderate volume, comfortable for extended listening
|
|
* 5. -10 dB is fairly loud, but not uncomfortable
|
|
* 6. -6 dB is loud, but not at full volume
|
|
* 7. -3 dB is very loud, approaching system limits
|
|
* 8. -1 dB is extremely loud, just below maximum
|
|
* 9. -0 dB is maximum volume without distortion
|
|
*/
|
|
|
|
#define SAMPLING_RATE 44100
|
|
#define ASCII_METER_WIDTH 20
|
|
#define FRAMES_PER_SECOND 30
|
|
#define MIN_DECIBEL -60
|
|
#define MAX_DECIBEL 0
|
|
#define DEBUG_LOG 1
|
|
|
|
sig_atomic_t g_done;
|
|
|
|
void on_signal(int sig) {
|
|
g_done = 1;
|
|
}
|
|
|
|
// computes root of mean squares
|
|
double rms(float* p, int n) {
|
|
double s = 0;
|
|
for (int i = 0; i < n; ++i)
|
|
s += p[i] * p[i];
|
|
return sqrt(s / n);
|
|
}
|
|
|
|
// converts rms to decibel
|
|
double rms_to_db(double rms) {
|
|
double db = 20 * log10(rms);
|
|
db = fmin(db, MAX_DECIBEL);
|
|
db = fmax(db, MIN_DECIBEL);
|
|
return db;
|
|
}
|
|
|
|
int main() {
|
|
signal(SIGINT, on_signal);
|
|
|
|
// how many samples should we process at once
|
|
int chunkFrames = SAMPLING_RATE / FRAMES_PER_SECOND;
|
|
|
|
// configure cosmo audio
|
|
struct CosmoAudioOpenOptions cao = {0};
|
|
cao.sizeofThis = sizeof(struct CosmoAudioOpenOptions);
|
|
cao.deviceType = kCosmoAudioDeviceTypeCapture;
|
|
cao.sampleRate = SAMPLING_RATE;
|
|
cao.bufferFrames = chunkFrames * 2;
|
|
cao.debugLog = DEBUG_LOG;
|
|
cao.channels = 1;
|
|
|
|
// connect to microphone
|
|
int status;
|
|
struct CosmoAudio* ca;
|
|
status = cosmoaudio_open(&ca, &cao);
|
|
if (status != COSMOAUDIO_SUCCESS) {
|
|
fprintf(stderr, "failed to open microphone: %d\n", status);
|
|
return 1;
|
|
}
|
|
|
|
// allocate memory for audio work area
|
|
float* chunk = malloc(chunkFrames * sizeof(float));
|
|
if (!chunk) {
|
|
fprintf(stderr, "out of memory\n");
|
|
return 1;
|
|
}
|
|
|
|
while (!g_done) {
|
|
|
|
// wait for full chunk of audio to become available
|
|
int need_in_frames = chunkFrames;
|
|
status = cosmoaudio_poll(ca, &need_in_frames, NULL);
|
|
if (status != COSMOAUDIO_SUCCESS) {
|
|
fprintf(stderr, "failed to poll microphone: %d\n", status);
|
|
return 2;
|
|
}
|
|
|
|
// read audio frames from microphone ring buffer
|
|
status = cosmoaudio_read(ca, chunk, chunkFrames);
|
|
if (status != chunkFrames) {
|
|
fprintf(stderr, "failed to read microphone: %d\n", status);
|
|
return 3;
|
|
}
|
|
|
|
// convert audio chunk to to ascii meter
|
|
char s[ASCII_METER_WIDTH + 1] = {0};
|
|
double db = rms_to_db(rms(chunk, chunkFrames));
|
|
double db_range = MAX_DECIBEL - MIN_DECIBEL;
|
|
int filled_length = (db - MIN_DECIBEL) / db_range * ASCII_METER_WIDTH;
|
|
for (int i = 0; i < ASCII_METER_WIDTH; ++i) {
|
|
if (i < filled_length) {
|
|
s[i] = '=';
|
|
} else {
|
|
s[i] = ' ';
|
|
}
|
|
}
|
|
printf("\r%s| %+6.2f dB", s, db);
|
|
fflush(stdout);
|
|
}
|
|
printf("\n");
|
|
|
|
// clean up resources
|
|
status = cosmoaudio_close(ca);
|
|
if (status != COSMOAUDIO_SUCCESS) {
|
|
fprintf(stderr, "failed to close microphone: %d\n", status);
|
|
return 5;
|
|
}
|
|
free(chunk);
|
|
}
|