summaryrefslogtreecommitdiff
path: root/alsa-record-sound
diff options
context:
space:
mode:
authorFreeArtMan <dos21h@gmail.com>2016-10-16 20:50:22 +0100
committerFreeArtMan <dos21h@gmail.com>2016-10-16 20:50:22 +0100
commitf51a4c1684a139418023e2ea2aea242d2cd18840 (patch)
tree0fbfde8f8e677927a7b597fa5b5af31c6dca2134 /alsa-record-sound
parent1af64014935ad7877bbeda1331fee514ff3502af (diff)
downloadcode-snippets-f51a4c1684a139418023e2ea2aea242d2cd18840.tar.gz
code-snippets-f51a4c1684a139418023e2ea2aea242d2cd18840.zip
Added record sound from microphone with alsa
Diffstat (limited to 'alsa-record-sound')
-rw-r--r--alsa-record-sound/Makefile2
-rw-r--r--alsa-record-sound/debug.h69
-rw-r--r--alsa-record-sound/record.c266
3 files changed, 337 insertions, 0 deletions
diff --git a/alsa-record-sound/Makefile b/alsa-record-sound/Makefile
new file mode 100644
index 0000000..4d62a06
--- /dev/null
+++ b/alsa-record-sound/Makefile
@@ -0,0 +1,2 @@
+make:
+ gcc record.c -o record -lasound
diff --git a/alsa-record-sound/debug.h b/alsa-record-sound/debug.h
new file mode 100644
index 0000000..a8bf211
--- /dev/null
+++ b/alsa-record-sound/debug.h
@@ -0,0 +1,69 @@
+#ifndef __RB_DEBUG_UTILS_H
+#define __RB_DEBUG_UTILS_H
+
+//what about kprintf?
+
+//config options
+#define PRINTF printf
+#define COLORIZE
+#define PRINT_LINENUM
+#define PRINT_FILENAME
+#define PRINT_DEBUG
+
+
+//use color
+#ifdef COLORIZE
+ #define D_COLOR "1;32m"
+ #define D_COLOR_S "\033[" D_COLOR
+ #define D_COLOR_E "\033[0m"
+ #define E_COLOR "1;31m"
+ #define E_COLOR_S "\033[" E_COLOR
+ #define E_COLOR_E "\033[0m"
+#else
+ #define D_COLOR
+ #define D_COLOR_S
+ #define D_COLOR_E
+ #define E_COLOR
+ #define E_COLOR_S
+ #define E_COLOR_E
+#endif
+
+//print debug line
+#ifdef PRINT_LINENUM
+ #define PRINT_LINE_F "LINE:%d "
+ #define PRINT_LINE_D __LINE__
+#else
+ #define PRINT_LINE_F ""
+ #define PRINT_LINE_D ""
+#endif
+
+//print
+#ifdef PRINT_FILENAME
+ #define PRINT_FILE_F "FILE:%s "
+ #define PRINT_FILE_D __FILE__
+#else
+ #define PRINT_FILE_F ""
+ #define PRINT_FILE_D ""
+#endif
+
+//print debug string
+#ifdef PRINT_DEBUG
+ #define PRINT_DEBUG_F "Debug: "
+#else
+ #define PRINT_DEBUG_F ""
+#endif
+
+#define PRINT( format, args ... ) PRINTF( D_COLOR_S PRINT_DEBUG_F \
+ PRINT_FILE_F PRINT_LINE_F format D_COLOR_E, PRINT_FILE_D, \
+ PRINT_LINE_D, ##args);
+
+#define ERROR( format, args ... ) PRINTF( E_COLOR_S PRINT_DEBUG_F \
+ PRINT_FILE_F PRINT_LINE_F format E_COLOR_E, PRINT_FILE_D, \
+ PRINT_LINE_D, ##args);
+
+#define PNL() PRINT("\n");
+
+#define ENL() ERROR("\n");
+
+
+#endif
diff --git a/alsa-record-sound/record.c b/alsa-record-sound/record.c
new file mode 100644
index 0000000..ed9c2e1
--- /dev/null
+++ b/alsa-record-sound/record.c
@@ -0,0 +1,266 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <alsa/asoundlib.h>
+
+#include "debug.h"
+
+#define AERR(S) if (err<0) {printf("error line %d:"S" %s\n", __LINE__, snd_strerror(err));};
+
+typedef struct audio_params
+{
+ snd_pcm_format_t format;
+ unsigned int channels;
+ unsigned int rate;
+} audio_params;
+
+int main(int argc, char **argv)
+{
+ /* variables */
+ int i;
+ int err;
+ size_t n;
+ snd_pcm_uframes_t chunk_size;
+ size_t chunk_bytes;
+ snd_output_t *log;
+ const snd_pcm_channel_area_t *areas;
+ snd_pcm_uframes_t mmap_offset, mmap_size = chunk_size;
+ long long max_file_size = 0;
+ FILE *fout=NULL;
+
+ /* audio params */
+ char audio_name[] = "hw:0";
+ int open_mode = 0;
+ audio_params params;
+ unsigned int rate;
+ unsigned int buffer_time;
+ unsigned int period_time;
+ snd_pcm_uframes_t period_frames = 0;
+ snd_pcm_uframes_t buffer_frames = 0;
+ int monotonic = 0;
+ int can_pause = 0;
+ int avail_min = -1;
+ int start_delay = 0;
+ int stop_delay = 0;
+ snd_pcm_uframes_t start_threshold, stop_threshold;
+ size_t significant_bits_per_sample, bits_per_sample, bits_per_frame;
+ u_char *audiobuf = NULL;
+ uint64_t fdcount=0;
+
+ /* audio variables */
+ snd_pcm_t *handle;
+ snd_pcm_hw_params_t *hwparams;
+ snd_pcm_sw_params_t *swparams;
+ snd_pcm_uframes_t buffer_size;
+ snd_pcm_access_mask_t *mask;
+
+ /* set recording params */
+ params.channels = 2;
+ params.rate = 44100;
+ params.format = SND_PCM_FORMAT_S16_LE;
+
+ /* set device */
+ err = snd_pcm_open(&handle, audio_name, SND_PCM_STREAM_CAPTURE, open_mode);
+ AERR("Cant open");
+
+ /* alloc hw params */
+ err = snd_pcm_hw_params_malloc(&hwparams);
+ AERR("hw params alloc");
+
+ err = snd_pcm_hw_params_any(handle, hwparams);
+ AERR("hw params initialisation");
+
+ /* alooc sw params */
+ err = snd_pcm_sw_params_malloc(&swparams);
+ AERR("sw params alloca");
+
+ /* mmaped buffer */
+ mask = alloca(snd_pcm_access_mask_sizeof());
+ snd_pcm_access_mask_none(mask);
+ snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+ snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+ snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX);
+ err = snd_pcm_hw_params_set_access_mask(handle, hwparams, mask);
+ AERR("Cannot set access mask");
+
+ /* set channels */
+ err = snd_pcm_hw_params_set_channels(handle, hwparams, params.channels );
+ AERR("Cannot set channels");PNL();
+
+ /* set and check rate */
+ rate = params.rate;
+ err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &params.rate, 0);
+ if ((float)rate*1.05 < params.rate || (float)rate*0.95>params.rate)
+ {
+ printf("Inaccurare rate setting\n");
+ }
+
+ /*set buffer time and perioid max*/
+ rate = params.rate;
+ if (buffer_time == 0 && buffer_frames == 0)
+ {
+ err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0);
+ AERR("Cannt get buffer time max");
+ if (buffer_time > 500000)
+ buffer_time = 500000;
+ }
+ if (period_time == 0 && period_frames == 0)
+ {
+ if (buffer_time > 0)
+ period_time = buffer_time / 4;
+ else
+ period_frames = buffer_frames / 4;
+ }
+ if (period_time > 0)
+ {
+ err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0);
+ } else {
+ err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_frames, 0);
+ }
+ AERR("Cant set period");PNL();
+ if (buffer_time > 0)
+ {
+ err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0);
+ } else {
+ err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_frames);
+ }
+ AERR("Cant set buffer time/size");PNL();
+
+ monotonic = snd_pcm_hw_params_is_monotonic(hwparams);
+ can_pause = snd_pcm_hw_params_can_pause(hwparams);
+
+ err = snd_pcm_hw_params(handle, hwparams);
+ if (err < 0)
+ {
+ printf("Unable to install hw params:\n");
+ snd_pcm_hw_params_dump(hwparams, log);
+ exit(EXIT_FAILURE);
+ }
+
+ snd_pcm_hw_params_get_period_size(hwparams, &chunk_size, 0);
+ snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size);
+ if (chunk_size == buffer_size)
+ {
+ printf("Can't use period equal to buffer size (%lu == %lu)\n",
+ chunk_size, buffer_size);
+ exit(EXIT_FAILURE);
+ }
+
+ snd_pcm_sw_params_current(handle, swparams);
+ if (avail_min < 0)
+ {
+ n = chunk_size;
+ } else {
+ n = (double)rate * avail_min * 1000000;
+ }
+ err = snd_pcm_sw_params_set_avail_min(handle, swparams, n);
+ AERR("Couldnt set avaliable min");
+
+ /* round up to closest transfer boundry */
+ n = buffer_size;
+ if (start_delay <= 0) {
+ start_threshold = n + (double) rate * start_delay / 1000000;
+ } else
+ start_threshold = (double) rate * start_delay / 1000000;
+ if (start_threshold < 1)
+ start_threshold = 1;
+ if (start_threshold > n)
+ start_threshold = n;
+ err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
+ assert(err >= 0);
+ if (stop_delay <= 0)
+ stop_threshold = buffer_size + (double) rate * stop_delay / 1000000;
+ else
+ stop_threshold = (double) rate * stop_delay / 1000000;
+ err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
+ assert(err >= 0);
+
+ err = snd_pcm_sw_params(handle, swparams);
+ AERR("Unable to install sw params\n");PNL();
+
+ /*do we neet setup_chmap?*/
+
+ //snd_pcm_dump(handle, log);PNL();
+
+ bits_per_sample = snd_pcm_format_physical_width(params.format);
+ printf("!bits_per_sample=%d\n",bits_per_sample);
+ significant_bits_per_sample = snd_pcm_format_width(params.format);
+ bits_per_frame = bits_per_sample * params.channels;
+ chunk_bytes = chunk_size * bits_per_frame / 8;
+ printf("INFO: audio buffer size %d bytes\n",chunk_bytes);
+ audiobuf = realloc(audiobuf, chunk_bytes);
+ if (audiobuf == NULL) {
+ printf("not enough memory\n");
+ exit(EXIT_FAILURE);
+ }
+ // fprintf(stderr, "real chunk_size = %i, frags = %i, total = %i\n", chunk_size, setup.buf.block.frags, setup.buf.block.frags * chunk_size);
+
+ /* show mmap buffer arragment */
+
+
+ err = snd_pcm_mmap_begin(handle, &areas, &mmap_offset, &mmap_size);
+ if (err < 0) {
+ printf("snd_pcm_mmap_begin problem: %s\n", snd_strerror(err));
+ exit(EXIT_FAILURE);
+ }
+ for (i = 0; i < params.channels; i++)
+ fprintf(stderr, "mmap_area[%i] = %p,%u,%u (%u)\n", i, areas[i].addr, areas[i].first, areas[i].step, snd_pcm_format_physical_width(params.format));
+ /* not required, but for sure */
+ snd_pcm_mmap_commit(handle, mmap_offset, 0);
+
+ buffer_frames = buffer_size; /* for position test */
+
+ /* get size of record for current config */
+
+ max_file_size = snd_pcm_format_size(params.format, params.rate*params.channels);
+ printf("INFO: Date %d byters per record\n", max_file_size);
+
+ /* open file where to record */
+ fout = fopen("foo_r2.wav","w");
+ if (fout==NULL)
+ {
+ printf("Couldnt open record file");
+ exit(0);
+ }
+
+ /* recording loop */
+ {
+ size_t rest=0;
+ size_t r=0;
+ size_t idx=0;
+ u_char *data = audiobuf;
+ size_t c = chunk_bytes;
+ size_t f = c * 8 / bits_per_frame;
+ rest = f*100;
+ idx = 0;
+ //fdcount = 0;
+ while (rest > 1)
+ {
+ r = snd_pcm_mmap_readi(handle,data, f);
+ if ((r == -EAGAIN) || ((r >= 0) && (r < rest)))
+ {
+ //snd_pcm_wait(handle, 100);
+ } else
+ {
+ printf("Buffer reading problem %d\n",r);
+ //break;
+ }
+ rest -= r;
+ err = fwrite(audiobuf,1,r*bits_per_frame/8,fout);
+ if (err != r*bits_per_frame/8)
+ printf("Not all data saved %d\n",err);
+ }
+ }
+ fclose(fout);
+
+ /* free audio resources */
+ snd_pcm_close(handle);
+ free(audiobuf);
+ //snd_output_close(log);
+ snd_config_update_free_global();
+
+
+ return 0;
+} \ No newline at end of file