Skip to content

Commit

Permalink
Moved playback files
Browse files Browse the repository at this point in the history
  • Loading branch information
NebiyouTen committed Mar 20, 2019
1 parent 0024164 commit 463be22
Show file tree
Hide file tree
Showing 6 changed files with 375 additions and 0 deletions.
10 changes: 10 additions & 0 deletions PCM_Playback/Makefile
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 added PCM_Playback/PCM_Wav_Play
Binary file not shown.
142 changes: 142 additions & 0 deletions PCM_Playback/PCM_Wav_Play.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* 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 "test.wav"
#define SAMPLE_RATE 8000

/*
* @main program. It opens a PCM devices, initializes paramters and
* makes a call to the wave_play program by passing a filename, a PCM
* handle and number of frames.
*
* */
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;
unsigned int size, sample_rate, period_time, loop_time, num_loops;


// Get list of devie names
char **hints;
return_val = snd_device_name_hint(-1, "pcm", (void***)&hints);
char ** n = hints;
while (*n != NULL) {

char *name = snd_device_name_get_hint(*n, "NAME");
printf("Devide found : %s \n", name);
if (name != NULL && 0 != strcmp("null", name)) {
//Copy name to another buffer and then free it
free(name);
}
n++;
}//End of while
// end list of devie name retrival

// 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(&params);
// 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);
}
snd_pcm_hw_params_set_rate(handle, params,
sample_rate, 0);

// 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;

}
1 change: 1 addition & 0 deletions PCM_Playback/gcc_compile_script
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
189 changes: 189 additions & 0 deletions PCM_Playback/wave_play.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
*
* 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];

/*
* @Function to read 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 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\n\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 );
// 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/%d\n",i,\
// number_of_samples );
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;
}
33 changes: 33 additions & 0 deletions PCM_Playback/wave_play.h
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);

0 comments on commit 463be22

Please sign in to comment.