Audio recording and playback
Original Assignment
Using the ISD1110 voice chip, and a speaker and microphone provided to you, demonstrate a circuit that allows you to record and play back sounds. Demonstrate it under PIC control. See if you can record and play back multiple sounds, as chosen by the PIC.
Overview
The ISD1100 voice chip is a single chip solution which allows for both the recording and playback of a 10 second audio clip, either in its entirety or in small pieces. Using only an electret microphone, a speaker and minimal circuitry, mainly filtering, a simple system can be developed.
An electret microphone such as is easy to use with the chip. For more information on electret microphone theory and operation visit the microphones page. A 16 ohm speaker is recommended for use with the ISD1110.
The chip can be run under pic control. Using the code below, the pic can start the recording process, enable the playback and even address specific locations of the recording.
Both recording and playback are enabled by connecting the corresponding pin on the chip to ground or digital low. A specific portion of the recording is accessed by sending an 8-bit address to the ISD1110 chip.
Circuit
Code
#include <18f4520.h> #include <string.h> #include <stdlib.h> #fuses HS,NOLVP,NOWDT,NOPROTECT #use delay(clock=40000000) #use rs232(baud=9600, UART1) // hardware setup #define HIGH 1 #define LOW 0 #define REC_PIN PIN_C2 #define PLE_PIN PIN_C1 #define PLL_PIN PIN_C0 // software setup #define BUFFER 100 #define IS_CMD(i, c) (!stricmp((i), (c))) #define ENTER 0x0D #define DUR_PER_MEM_LOC 125 // ms #define MAX_MEM_LOC 80 #define MAX_DURATION 10000 // ms #define BASE 10 #define PULSE_ENABLE 10 // ms #define LOOP_ENABLE 0b11001000 // A7, A6, & A3 on (see ISD1100 data sheet) char REC_CMD[] = "rec"; char PLAY_CMD[] = "play"; char LOOP_CMD[] = "loop"; char CHUNK_CMD[] = "chunk"; /** * activates the play pin with a level signal */ void play_l(int8 a, int16 d) { printf("<<>> you sent a play segment @ %u for %lu command\r\n", a, d); output_d(a); output_bit(PLL_PIN, LOW); delay_ms(d); output_bit(PLL_PIN, HIGH); output_d(LOW); } /** * activates the looping feature */ void loop(int16 d) { printf("<<>> you sent a loop @ %u for %lu command\r\n", a, d); output_d(LOOP_ENABLE); output_bit(PLE_PIN, LOW); output_bit(PLE_PIN, HIGH); delay_ms(d); output_bit(PLL_PIN, LOW); output_bit(PLL_PIN, HIGH); output_d(LOW); } /** * activates the play pin with pulse signal */ void play_e(int8 a) { printf("<<>> you sent a play @ %u command\r\n", a); output_d(a); output_bit(PLE_PIN, LOW); delay_ms(PULSE_ENABLE); output_bit(PLE_PIN, HIGH); output_d(LOW); } /** * activates the record pin with a level signal */ void record(int8 a, int16 d) { printf("<<>> you sent a record @ %u for %lu command\r\n", a, d); output_d(a); output_bit(REC_PIN, LOW); delay_ms(d); output_bit(REC_PIN, HIGH); output_d(LOW); } /** * parses a command from an RS-232 prompt */ void run_cmd(char *input) { int16 addr, dur; char *delim = " ;"; char *cmd; cmd = strtok(input, delim); addr = strtoul(strtok(NULL, delim), NULL, BASE); dur = strtoul(strtok(NULL, delim), NULL, BASE); if(!dur) { dur = MAX_DURATION; } if(addr > MAX_MEM_LOC) { printf("<<>> oops address is out of range (0 <= addr <= %u).\r\n", MAX_MEM_LOC); } else if(IS_CMD(cmd, REC_CMD)) { record(addr, dur); } else if(IS_CMD(cmd, PLAY_CMD)) { play_e(addr); } else if(IS_CMD(cmd, LOOP_CMD)) { loop(dur); } else if(IS_CMD(cmd, CHUNK_CMD)) { play_l(addr, dur); } else { printf("<<>> oops invalid command \"%s\", try again!\r\n", cmd); } } /** * event loop */ void main(void) { int i; char input[BUFFER + 1]; // need to make space for the null character output_d(LOW); output_bit(REC_PIN, HIGH); output_bit(PLE_PIN, HIGH); output_bit(PLL_PIN, HIGH); while(TRUE) { // reset parameters i = 0; memset(input, '\0', sizeof(input)); // gather input while(i < BUFFER && (input[i] = getc()) != ENTER) { putc(input[i]); i++; } printf("\r\n"); // check input if(i == BUFFER) { printf("<<>> ERROR: your input is too long\r\n"); } else { run_cmd(input); } } }