Experiment 6 The Real World Interface Instructions You are required to design, code, test and document the C program from the experiment listed below. You should prepare the pseudocode for the program prior to the laboratory session. All code written should be fully documented including headers and comments.. You may use the various run-time C library subroutines to help you with your designs. The list of some useful subroutines are included on the website for this course Experiment Introduction The soundcard is a common peripheral found in all PCs. All hardware connected to the PCs are known as devices and link into the Operating System through device drivers. The device driver is a piece of software that runs the hardware. All devices in UNIX appear like files. This means that to talk to a device you must access its filename. In UNIX, all the devices can be found in the /dev directory. To talk to the soundcard s device driver we need to access /dev/dsp. Since a device driver appears like a file to the UNIX operating system then we can open, close, read, and write to the device driver. Opening a device intialises the hardware. Writing to a device writes a value to the hardware. Reading from a device reads a value from the hardware. Closing a device cleans out any buffers. In the case of the soundcard we must do the following: Apply a file open on /dev/dsp to initialise the soundcard. Note that the C function open() must be used here. Apply a file write on /dev/dsp to write a value to the soundcard. Note that the C function write() must be used here. Apply a file read on /dev/dsp to read a value from the soundcard. Note that the C function read() must be used here. All reading and writing to the file is buffered. This means that you must specify an array that will be used as a buffer by the device driver for all input and output. If you are writing to the device driver then the entire contents of the array is written to the device. If you are reading from the device driver then the array is filled with the values read from the device. A template for the soundcard programming can be found on the course website. This template contains an initialisation function for the soundcard. It opens the soundcard device, sets the data format to unsigned char, sets the buffering method, and sets the speed that the data is output from the soundcard or input from the soundcard. The definitions for the file access functions read() and write() can be found at the end of this experiment s documentation. 1
Experiment The ICP Compact Disc Player Compact Discs have the music encoded into digital form and stored as logic 0 s and logic 1 s on the disc. You are going to play a digitized waveform contained in a file on your computer through the Digital to Analogue Converter (DAC) to a speaker. Write a program called play that reads from a binary file containing speech etc found on the course website. There are many speech/sound files. The files are of varying size and sampling rates. Your program should store that data from the file into an array. Once all the data has been read then it should be written to the soundcard device. The array should be dynamically allocated based upon the file size. The program must ask the user for the size of the file in KB. Note that there is no portable way to determine the file size in C. You can adjust the sampling rate (speed) to the following possible values. This is done through setting the value in the argument to the soundcard routine. 8000 8K sampling rate 11000 11K sampling rate 22000 22K sampling rate 44000 44K sampling rate. The output will be an approximate representation of the input signal that was originally digitized. You will learn how to improve the quality of the digitized sound in later courses. The ICP Frequency Generator Write a program using the soundcard to output a 1KHz tome to the speaker. Make the duration of the tone about one second. The ICP Keyboard Modify the above program to play different notes depending upon the keys pressed on the keyboard. The frequencies for the different notes in an octave are as follows: Note Frequency (Hz) C 264 D 297 E 330 F 352 G 296 A 440 B 495 C 528 The template for experiment 6 and function information can be found on the following pages. 2
write( ) NAME write - write to a file descriptor SYNOPSIS #include <unistd.h> ssize_t write(int fd, const void *bu:t; size_t count); I DESCRIPTION write writes up to count bytes to the file referenced by the file descriptor fd from the buffer starting at buf POSIX requires that a read() which can be proved to occur after a write() has returned returns the new data. Note that not all file systems are POSIX conforming. RETURN VALUE On success, the number of bytes written are returned (zero indicates nothing was written). On error, -1 is returned, and errno is set appropriately. If count is zero and the file descriptor refers to a regular file, 0 will be returned without causing any other effect. For a special file, the results are not portable. read( ) NAME read - read ftom a file descriptor SYNOPSIS #include <unistd.h> ssize_t read(int fd, void *buf, size_t count); DESCRIPTION reado attempts to read up to count bytes from file descriptor fd into the buffer starting at buf. If count is zero, read() returns zero and has no other results. If count is greater than SSIZE_MAX, the result is unspecified. RETURN VALUE On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number. It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are actually available right now (maybe because we were close to end-of-file, or because we are reading from a pipe, or from a terminal), or because reado was interrupted by a signal. On error, -1 is returned, and errno is set appropriately. In this case it is left unspecified whether the file position (if any) changes. 3
Template #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <linux/soundcard.h> #include <math.h> int main(void) unsigned char buff[200] ; int i,audio ; float SampleRate=11000 ; /* initialise the sound device to the sample rate specified */ audio=initialise_sound_device(samplerate); /* this can be removed as it is just filling the buffer */ /* This example fills the buffer and writes it to the sound card */ for (i=0; i<200; i++) buff[i]=i ; write(audio,buff,200) ; /* write 200 bytes to the soundcard */ /* close the sound device */ close(audio); /* leave the program */ return (EXIT_SUCCESS) ; int Initialise_Sound_Device(int SampleRate) int format=afmt_u8; int channels=1; int stereo=0; int speed; int audio_fd=0; int frag_arg = 0x7FFF007; int sample_size=2; speed=samplerate ; /* open the sound device */ if((audio_fd = open("/dev/dsp",o_wronly)) == -1) perror("/dev/dsp"); /* set data format */ if(ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format) ==-1) 4
perror("sndctl_dsp_setfmt"); /* set stereo or mono */ if(ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) ==-1) perror("sndctl_dsp_channels"); /* set the sampling rate */ if(ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed) ==-1) perror("sndctl_dsp_speed"); /* define how the buffers are to be used */ if(ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_arg) ==-1) perror("sndctl_dsp_setfragment"); /* return the file handle for use outside this initialising module */ return(audio_fd); 5