-
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
0 parents
commit 35b9dd8
Showing
8 changed files
with
339 additions
and
0 deletions.
There are no files selected for viewing
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,10 @@ | ||
CC = gcc | ||
CFLAGS = -Wall | ||
DEPS = wave.h | ||
OBJ = PCM_Wav_Play.o wave.o | ||
|
||
%.o %.c $(DEPS) | ||
$(cc) $(CFLAGS) -c -o $@ $< | ||
|
||
PCM_Wav_Play : $(OBJ) | ||
gcc $(CFLAGS) -o $@ $^ |
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,118 @@ | ||
/* | ||
* A simple code to read from a wav file | ||
* and play it. | ||
* | ||
* Adopted from the linux journal | ||
* https://www.linuxjournal.com/article/6735 | ||
* | ||
* */ | ||
|
||
// Tell Alsa to use newer version of its API | ||
#define ALSA_PCM_NEW_HW_PARAMS_API | ||
|
||
#include <alsa/asoundlib.h> | ||
#include "wave_play.h" | ||
|
||
#define SECOND 1000000 | ||
#define file_name "sample_wav.wav" | ||
/* | ||
* | ||
* | ||
* | ||
* */ | ||
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 = "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 device | ||
if ( (return_val = snd_pcm_open(&handle, device_name, | ||
SND_PCM_STREAM_PLAYBACK, 0)) < 0){ | ||
fprintf(stderr, | ||
"unable to open pcm device %s : %s\n", device_name \ | ||
, snd_strerror(return_val)); | ||
exit(1); | ||
} | ||
fprintf(stdout, "PCM Device \"%s\" successfully opened\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 = 8000; | ||
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); | ||
} | ||
// 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 actual period size. It could be different from | ||
// the previously set value. | ||
snd_pcm_hw_params_get_period_size(params, &frames,0); | ||
fprintf(stdout,"Got a period size of %d \n", frames); | ||
|
||
// This function will open a wav file and play it using | ||
// the handle. | ||
read_wave_and_play(file_name, handle, frames); | ||
// Drain and close the PCM handle | ||
snd_pcm_drain(handle); | ||
snd_pcm_close(handle); | ||
|
||
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 @@ | ||
# Alsa_Wave_Play |
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_Wav_Play.c wave_play.c -o PCM_Wav_Play -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,176 @@ | ||
/* | ||
* | ||
* 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_play.h" | ||
#include <unistd.h> | ||
#include <string.h> | ||
#include <stdlib.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; | ||
unsigned char temp_buffer[4]; | ||
unsigned char temp_buffer_2[2]; | ||
|
||
int read_wave_and_play(char *file_name, snd_pcm_t *handle, | ||
snd_pcm_uframes_t frames){ | ||
|
||
int ret, data_size; | ||
long number_of_samples, size_of_samples, i = 0; | ||
long low_limit=0l, high_limit = 0l; | ||
float duration_in_sec; | ||
char * data_temp_buffer; | ||
|
||
|
||
fprintf(stdout,"Wave file reading started \n"); | ||
|
||
if ( (file_ptr = fopen(file_name, "rb") ) == NULL){ | ||
printf("error in opening file"); | ||
exit(1); | ||
} | ||
|
||
// read header data | ||
ret = fread(wave_header.riff, sizeof(wave_header.riff),1,file_ptr); | ||
printf("RIFF header values %s .\n",wave_header.riff); | ||
// read file size | ||
ret = fread(temp_buffer, sizeof(temp_buffer), 1, file_ptr); | ||
wave_header.file_size = temp_buffer[0] | (temp_buffer[1] << 8) | \ | ||
(temp_buffer[2] << 16) | (temp_buffer[3] << 24); | ||
printf("Wav file size %u KB.\n",wave_header.file_size / 1024); | ||
// get wav header | ||
ret = fread(wave_header.wave, sizeof(wave_header.wave),1, file_ptr); | ||
printf("Wave marker is %s .\n",wave_header.wave); | ||
// fmt marker | ||
ret = fread(wave_header.fmt_chunk_marker, \ | ||
sizeof(wave_header.fmt_chunk_marker), 1, file_ptr); | ||
printf("Fmt chunk marker is %s .\n",wave_header.fmt_chunk_marker); | ||
// read fmt length | ||
ret = fread(temp_buffer, sizeof(temp_buffer), 1, file_ptr); | ||
wave_header.length_of_fmt = temp_buffer[0] | (temp_buffer[1] << 8) | \ | ||
(temp_buffer[2] << 16) | (temp_buffer[3] << 24); | ||
printf("Length of fmt header %u B.\n", wave_header.length_of_fmt); | ||
// get format type | ||
ret = fread(temp_buffer_2, sizeof(temp_buffer_2), 1, file_ptr); | ||
wave_header.format_type = temp_buffer_2[0] | temp_buffer_2[1] << 8 ; | ||
switch(wave_header.format_type){ | ||
case (1): printf("Format type PCM \n"); | ||
break; | ||
default: printf("Format type other \n"); | ||
break; | ||
} | ||
// get channels | ||
ret = fread(temp_buffer_2, sizeof(temp_buffer_2), 1, file_ptr); | ||
wave_header.channels = temp_buffer_2[0] | temp_buffer_2[1] << 8 ; | ||
printf("Channels %u .\n", wave_header.channels); | ||
// read sample rate | ||
ret = fread(temp_buffer, sizeof(temp_buffer), 1, file_ptr); | ||
wave_header.sample_rate = temp_buffer[0] | (temp_buffer[1] << 8) | \ | ||
(temp_buffer[2] << 16) | (temp_buffer[3] << 24); | ||
printf("Sample rate %u .\n",wave_header.sample_rate); | ||
// read byte rate | ||
ret = fread(temp_buffer, sizeof(temp_buffer), 1, file_ptr); | ||
wave_header.byterate = temp_buffer[0] | (temp_buffer[1] << 8) | \ | ||
(temp_buffer[2] << 16) | (temp_buffer[3] << 24); | ||
printf("Byte rate %u.\n",wave_header.byterate); | ||
// read block allignment | ||
ret = fread(temp_buffer_2, sizeof(temp_buffer_2), 1, file_ptr); | ||
wave_header.block_align = temp_buffer_2[0] | temp_buffer_2[1] << 8 ; | ||
printf("Block alignment %u .\n", wave_header.block_align); | ||
// get bit's per sample | ||
ret = fread(temp_buffer_2, sizeof(temp_buffer_2), 1, file_ptr); | ||
wave_header.bits_per_sample = temp_buffer_2[0] | temp_buffer_2[1] << 8 ; | ||
printf("Bit's per sample %u .\n", wave_header.bits_per_sample); | ||
// read data marker | ||
ret = fread(wave_header.data_chunk_header, | ||
sizeof(wave_header.data_chunk_header), | ||
1, file_ptr); | ||
printf("data_chunk_header %s .\n",wave_header.data_chunk_header); | ||
// read data size | ||
ret = fread(temp_buffer, sizeof(temp_buffer), 1, file_ptr); | ||
wave_header.data_size = temp_buffer[0] | (temp_buffer[1] << 8) | \ | ||
(temp_buffer[2] << 16) | (temp_buffer[3] << 24); | ||
printf("Data size %u .\n",wave_header.data_size ); | ||
|
||
// calculate number of samples; | ||
size_of_samples = (wave_header.channels * \ | ||
wave_header.bits_per_sample)/8; | ||
number_of_samples = ( 8 * wave_header.data_size) | ||
/ (size_of_samples); | ||
duration_in_sec = (float) wave_header.file_size \ | ||
/ wave_header.byterate; | ||
printf("%lu samples, each %ld bytes, %f seconds \n", | ||
number_of_samples, size_of_samples, duration_in_sec); | ||
|
||
// Reading all data at once | ||
// get actual data size | ||
fseek(file_ptr, 0, SEEK_END); | ||
data_size = ftell(file_ptr) - HEADER_SIZE; | ||
printf("File size is %u %u %u\n", data_size, ftell(file_ptr) ); | ||
fseek(file_ptr, HEADER_SIZE, SEEK_SET); | ||
// Read all data at once | ||
if (!READ_in_CHUNKS){ | ||
data_temp_buffer = (char *) malloc(data_size ); | ||
ret = fread(data_temp_buffer, NUM_BYTES , data_size/NUM_BYTES, | ||
file_ptr); | ||
printf("Num samp is %d, read is %d \n", data_size/NUM_BYTES, | ||
ret); | ||
snd_pcm_writei(handle, data_temp_buffer, data_size/NUM_BYTES); | ||
free(data_temp_buffer); | ||
|
||
} | ||
else{ | ||
// reading chunks | ||
// allocate temp_buffer for each chunk | ||
data_temp_buffer = (char *) malloc(NUM_BYTES * frames); | ||
// get the number of samples/chunks | ||
number_of_samples = data_size/ (NUM_BYTES *frames); | ||
|
||
for (i=0; i< number_of_samples; i++){ | ||
|
||
ret = fread(data_temp_buffer, NUM_BYTES ,frames, file_ptr); | ||
printf("Reading sample %d of %d %lu samples \n",i,\ | ||
number_of_samples , sizeof(data_temp_buffer)); | ||
if (ret == 0) { | ||
fprintf(stderr, "file reading error \n"); | ||
break; | ||
} | ||
ret = snd_pcm_writei(handle, data_temp_buffer, frames); | ||
if (ret == -EPIPE) { | ||
///* EPIPE means underrun */ | ||
fprintf(stderr, "underrun occurred\n"); | ||
snd_pcm_prepare(handle); | ||
} else if (ret < 0) { | ||
fprintf(stderr, | ||
"error from writei: %s\n", | ||
snd_strerror(ret)); | ||
} else if (ret != (int)frames) { | ||
fprintf(stderr, | ||
"short write, write %d frames\n", ret); | ||
} | ||
} | ||
} | ||
free(data_temp_buffer); | ||
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,33 @@ | ||
|
||
/* | ||
* | ||
* 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{ | ||
|
||
unsigned char riff[4]; //Bytes for RIFF file format | ||
unsigned int file_size; // An int (4 bytes) for file size | ||
unsigned char wave[4]; // Chars for file headers | ||
unsigned char fmt_chunk_marker[4]; // fmt string data | ||
unsigned int length_of_fmt; // length of format data | ||
unsigned int format_type; // format type | ||
unsigned int channels; | ||
unsigned int sample_rate; | ||
unsigned int byterate; | ||
unsigned int block_align; | ||
unsigned int bits_per_sample; | ||
unsigned char data_chunk_header [4]; | ||
unsigned int data_size; | ||
|
||
}; | ||
|
||
|
||
int read_wave_and_play(char *file_name, snd_pcm_t *handle, | ||
snd_pcm_uframes_t frames); |