-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
04243c8
commit 0024164
Showing
6 changed files
with
317 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/* | ||
* A simple progrma that records a sound. | ||
* | ||
* Adopted from the linux journal | ||
* https://www.linuxjournal.com/article/6735 | ||
* | ||
* */ | ||
|
||
// Tell alsa to include the new library | ||
#define ALSA_PCM_NEW_HW_PARAMS_API | ||
|
||
#include <alsa/asoundlib.h> | ||
#include "wave.h" | ||
|
||
#define SAMPLE_RATE 8000 | ||
#define SECOND 1000000 | ||
#define NUMSECONDS 20 | ||
|
||
int main(){ | ||
|
||
// PCM device handle | ||
snd_pcm_t *handle; | ||
// Structure used to configure the PCM device | ||
snd_pcm_hw_params_t *params; | ||
// name of the device, default for now | ||
char * device_name = "plug:default"; | ||
// Variable to store return values of functions | ||
int return_val; | ||
// frames used to determine size of a period | ||
snd_pcm_uframes_t frames; | ||
// Buffer to store data to be captured or played | ||
char *buffer; | ||
//char * file_name = "sample_wav.wav"; | ||
unsigned int size, sample_rate, period_time, loop_time, num_loops; | ||
|
||
// open pcm for capturing | ||
if ( (return_val = snd_pcm_open(&handle, "plug:default", | ||
SND_PCM_STREAM_CAPTURE,0)) < 0 ){ | ||
fprintf(stderr, | ||
"unable to open pcm device %s : %s\n", device_name \ | ||
, snd_strerror(return_val)); | ||
exit(1); | ||
|
||
} | ||
|
||
printf("Devie '%s' opened successfully \n", device_name); | ||
|
||
// Allocate params | ||
snd_pcm_hw_params_alloca(¶ms); | ||
// Initialize with default values | ||
snd_pcm_hw_params_any(handle, params); | ||
|
||
|
||
// Set Configuration values in params | ||
// set access type to RW interleaved and | ||
// check function callback | ||
if (snd_pcm_hw_params_set_access(handle, params, | ||
SND_PCM_ACCESS_RW_INTERLEAVED) < 0 ){ | ||
fprintf(stderr, | ||
"unable to set access type to RW Interleaved"); | ||
exit(1); | ||
} | ||
// Set the data format to Signed 16-bit little-endian | ||
if (snd_pcm_hw_params_set_format(handle, params, | ||
SND_PCM_FORMAT_S16_LE) < 0 ){ | ||
fprintf(stderr, | ||
"unable to set format to Signed 16-bit little-endian"); | ||
exit(1); | ||
} | ||
// set setrio channels | ||
if (snd_pcm_hw_params_set_channels(handle, params, 2) < 0 ){ | ||
fprintf(stderr, | ||
"unable to set channel to sterio"); | ||
exit(1); | ||
} | ||
// sample rate of sample wav file is 256000 bits/second | ||
// Invalid argument error if Sample rate is higher than 200,000 | ||
sample_rate = SAMPLE_RATE; | ||
if (snd_pcm_hw_params_set_rate_near(handle, params, | ||
&sample_rate, 0) < 0){ | ||
fprintf(stderr, | ||
"unable to set sample rate to %d ",sample_rate); | ||
exit(1); | ||
} | ||
|
||
fprintf(stdout,"sample rate is = %d \n", sample_rate); | ||
|
||
|
||
// set period size to 32 frames. A frame has 2 samples, left and | ||
// right samples. A sample has 2 bytes, most and least significant. | ||
frames = 64; | ||
fprintf(stdout,"Set number of frames is %d \n", frames); | ||
if (snd_pcm_hw_params_set_period_size_near(handle, | ||
params, &frames, 0) < 0){ | ||
fprintf(stderr, | ||
"unable to set period size to %d frames",frames); | ||
exit(1); | ||
} | ||
// Finally, write the params to the actual hardware device | ||
if ((return_val = snd_pcm_hw_params(handle, params)) < 0) { | ||
fprintf(stderr, | ||
"unable to set hw parameters: %s\n", | ||
snd_strerror(return_val)); | ||
exit(1); | ||
} | ||
|
||
|
||
// get buffer size for one period | ||
snd_pcm_hw_params_get_period_size(params,&frames,0); | ||
fprintf(stdout,"Got 1 a period size of %d \n", frames); | ||
|
||
|
||
//size will be 4 * period size. | ||
size = frames * 4; | ||
// allocate a buffer with size of 'size' | ||
fprintf(stdout, "Malloc with size %d \n", size); | ||
|
||
buffer = (char *) malloc(size); | ||
|
||
// get one period time | ||
snd_pcm_hw_params_get_period_time(params, &loop_time, 0); | ||
|
||
num_loops = NUMSECONDS * SECOND / loop_time; | ||
|
||
return_val = write_wave(buffer, handle,params, frames, num_loops); | ||
|
||
// Drain and close the PCM handle | ||
snd_pcm_drain(handle); | ||
snd_pcm_close(handle); | ||
|
||
if (return_val < 0){ | ||
fprintf(stderr, "error in writing a file \n", return_val); | ||
exit(1); | ||
} | ||
|
||
|
||
return 0; | ||
|
||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
gcc -I. PCM_Capture.c wave.c -o PCM_Capture -lasound |
Binary file not shown.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
/* | ||
* | ||
* Wave.c | ||
* A simple program to parse wav and play files . | ||
* | ||
* Adopted from | ||
* http://truelogic.org/wordpress/2015/09/04/parsing-a-wav-file-in-c/ | ||
* | ||
* */ | ||
|
||
// Tell Alsa to use newer version of its API | ||
|
||
#define ALSA_PCM_NEW_HW_PARAMS_API | ||
|
||
#include <alsa/asoundlib.h> | ||
|
||
#include <stdio.h> | ||
#include "wave.h" | ||
#include <unistd.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <arpa/inet.h> | ||
|
||
#define TRUE 1 | ||
#define FALSE 0 | ||
#define READ_in_CHUNKS 1 | ||
#define HEADER_SIZE 44 | ||
#define NUM_BYTES 4 | ||
|
||
// struct for the | ||
struct WAV_HEADER wave_header; | ||
// file ptr | ||
FILE *file_ptr; | ||
#define FILENAME "test.wav"; | ||
|
||
/* | ||
* @Function to write a wav file and play it using | ||
* the PCM handle passed. | ||
* | ||
* Arguments: file_name: name of the wav file to be played | ||
* handle : Pointer to a PCM | ||
* frames : Number of frames to be written in the buffer | ||
* , if chunk mode is used | ||
* | ||
* Returns: integer: | ||
* | ||
* */ | ||
int write_wave(char *buffer, snd_pcm_t *handle, | ||
snd_pcm_hw_params_t *params, | ||
int frames, int length){ | ||
|
||
int return_val, sample_rate, data_length; | ||
char *file_name = FILENAME; | ||
|
||
fprintf(stdout,"Wave file writing started %lu \n" | ||
, sizeof(wave_header)); | ||
|
||
file_ptr = fopen(file_name , "w+"); | ||
|
||
/* | ||
* Write header first | ||
* | ||
* */ | ||
|
||
fprintf(stdout, "Allocated wave header %lu \n", sizeof(wave_header)); | ||
|
||
// riff header: hex encoded string for riff | ||
wave_header.riff = htonl(0X52494646); // riff header | ||
// write chunk size, zero for now will be updated once file written | ||
wave_header.file_size = 0; | ||
// write WAVE to format, encoded string | ||
wave_header.wave = htonl(0X57415645); | ||
// fmt chunk marker encoded string "fmt" | ||
wave_header.fmt_chunk_marker = htonl(0X666d7420); | ||
wave_header.length_of_fmt = 16; | ||
wave_header.format_type = 1; // PCM | ||
wave_header.channels = 2; | ||
wave_header.sample_rate = 8000; | ||
wave_header.byterate = 4 * 8000; | ||
wave_header.block_align = 4; | ||
wave_header.bits_per_sample = 16; | ||
wave_header.data_chunk_header = htonl(0x64617461); // "data" | ||
wave_header.data_size = 0; // fill it at the end | ||
|
||
fwrite(&wave_header, sizeof(wave_header), 1, file_ptr); | ||
|
||
|
||
/* | ||
* Write data now | ||
* | ||
* */ | ||
data_length = length; | ||
while (length > 0 ){ | ||
|
||
length -= 1; | ||
if ( (return_val = snd_pcm_readi(handle, buffer, frames)) | ||
== -EPIPE ){ | ||
// overrun occurs | ||
fprintf(stderr, "overrun occured \n"); | ||
snd_pcm_prepare(handle); | ||
}else if(return_val < 0){ | ||
fprintf(stderr, "error from read: %s \n", snd_strerror(return_val)); | ||
}else if( return_val != (int)frames ){ | ||
fprintf(stderr, "short write %d != %d bytes \n. ",return_val,(int)frames); | ||
} | ||
|
||
return_val = fwrite(buffer, frames , 4, file_ptr); | ||
|
||
if (return_val != 4){ | ||
|
||
printf(" Write to file error %d != %d \n", return_val, frames); | ||
fclose(file_ptr); | ||
return -1; | ||
|
||
} | ||
|
||
} | ||
|
||
// move pointer to beggning of file with offset of 4 | ||
// meaning points to file size | ||
fseek(file_ptr, NUM_BYTES , SEEK_SET); | ||
// set file size | ||
data_length = data_length * frames * NUM_BYTES | ||
+ (HEADER_SIZE - 2 * NUM_BYTES); | ||
fwrite(&data_length, 1, sizeof(uint32_t), file_ptr); | ||
|
||
// move pointer to point to data size header | ||
fseek(file_ptr, HEADER_SIZE - NUM_BYTES, SEEK_SET); | ||
data_length -= + (HEADER_SIZE - 2 * NUM_BYTES); | ||
fwrite(&data_length, 1, sizeof(uint32_t), file_ptr); | ||
|
||
fprintf(stdout, "Final datasize is %d \n",data_length); | ||
|
||
fclose(file_ptr); | ||
return 0; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
|
||
/* | ||
* | ||
* Wave.h | ||
* A header file for a simple wav file parser | ||
* Adopted from | ||
* http://truelogic.org/wordpress/2015/09/04/parsing-a-wav-file-in-c/ | ||
* | ||
* */ | ||
|
||
|
||
// A structure to hold header of a wave file | ||
struct WAV_HEADER{ | ||
|
||
uint32_t riff; //Bytes for RIFF file format | ||
uint32_t file_size; // An int (4 bytes) for file size | ||
uint32_t wave; // Chars for file headers | ||
uint32_t fmt_chunk_marker; // fmt string data | ||
uint32_t length_of_fmt; // length of format data | ||
uint16_t format_type; // format type | ||
uint16_t channels; | ||
uint32_t sample_rate; | ||
uint32_t byterate; | ||
uint16_t block_align; | ||
uint16_t bits_per_sample; | ||
uint32_t data_chunk_header ; | ||
uint32_t data_size; | ||
|
||
}; | ||
|
||
|
||
int read_wave_and_play(char *file_name, snd_pcm_t *handle, | ||
snd_pcm_uframes_t frames); | ||
|
||
|
||
|
||
int write_wave(char *buffer, snd_pcm_t *handle, | ||
snd_pcm_hw_params_t *params, int frames, int length); | ||
|
||
|