#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 #include #include #include #include #include /** * @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); }