tags:

views:

72

answers:

2

hey there, just practising and I had a question. I have a program (source below) that prints out a wave in text. when the wave hits the outside of the terminal I have it make a noise with a function called noise(). but when that function is called it pauses the animation until it completes making the noise, then the animation starts again.

I was wondering if anyone knew of a way for the two functions to happen at the same time. should I fork() it or is there a better way?

the code I'm refering to is the lattus function and the noise function.

bellow is the full source to my program:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <ao/ao.h>
#include <math.h>

#define BUF_SIZE 4096

int main (int argc, char *argv[]) {  //check for whitch effect to print
    int i = argc;
    for(i > 0; i--;) {
     switch(*argv[i]) {
      case '1':
       lattus();
       break;
      case '2':
       normal();
       break;
      case '3':
       noise(50);
       break;
      default:
       break;
     }
    }
}


char *randstring (char *buffer, int length) {    //genertate a random number
    int i = length;
    for(i >= 0; i--;) {
     buffer[i] = (rand() % 2) ? '1' : '0';
    }
    buffer[length] = 0;
    return buffer;
}

int normal(){     // normal drawing of 1's and 0's
    struct winsize w;
    ioctl(0, TIOCGWINSZ, &w);
    int width = w.ws_col;
    int height = w.ws_row;  //get terminal width and height
    char buffer[width*height + 1]; //create a buffer big enough to hold one draw to the screen
    int i = 25;
    while(i-- >= 0) {
     printf("%s\n", randstring(buffer, width*height)); //draw to screen
     usleep(50000);
    }
    system("clear");  //clear screen
}

int noise(int pitch) {
    int second = 1;
    int freq = (second * pitch);
    ao_device *device;
    ao_sample_format format;
    int default_driver;
    char *buffer;
    int buf_size;
    int sample;
    ao_initialize();
    default_driver = ao_default_driver_id(); 
    format.bits = 16;
    format.channels = 2;
    format.rate = 44100;
    format.byte_format = AO_FMT_LITTLE;
    buf_size = format.bits/8 * format.channels * format.rate;
    int b = 10;
    device = ao_open_live(default_driver, &format, NULL /* no options */);
    buffer = calloc(buf_size, sizeof(char));
    for (b = 0; b < format.rate; b++) {
     sample = (int)(1 * 532768.0 * sin(2 * M_PI * freq * ((float) b/format.rate)));
     /* Put the same stuff in left and right channel */
     buffer[2 * b] = buffer[2*b+2] = sample & 0xff;
     buffer[2*b+1] = buffer[2*b+3] = (sample >> 8) & 0xff;
    }
    ao_play(device, buffer, buf_size);
    buffer = 0;
    ao_shutdown();
}

int lattus (void) {
    struct winsize w;
    ioctl(0, TIOCGWINSZ, &w);
    int width = w.ws_col;  //get the terminal width
    char *buffer1 = malloc(sizeof(char) * (width + 1)); //create 3 buffers for each segment
    char *buffer2 = malloc(sizeof(char) * (width + 1)); //each big enough to hold the width of the terminal
    char *buffer3 = malloc(sizeof(char) * (width + 1));
    int first = 1;   //how many before the space
    int second = width - 8;  //how many in the middle of the space
    int third = 1;   //how many at the end of the space
    int i = 1000;   //draw 1000 lines
    int on = 0;   //switch for growing and shrinking
    while(i-- >= 0) {
     usleep(9000);
     if(first == 1 && third == 1 && second == width - 8 || second == width - 9) { //is it at min?
      if(second % 2 == 0) {  //is it an even number (had problems with buffer if it was odd)
       second = second - 2;
      } else {
       second = second - 3;
      }
      first ++;
      third ++;
      on = 0;  //keep growing
      noise(10); //make lower noise
     } else if(first == (width - 8) / 2 && third == (width - 8) / 2 && second == 2) { //untill it gets to max
      if(second % 2 == 0) {
       second = second + 2;
      } else {
       second = second + 1;
      }
      third --;
      first --;
      on = 1;  //start shrinking
      noise(30); //make higher noise
     } else if(on == 0) { //else if suppost to grow, grow
      second = second - 2;
      third ++;
      first ++;
     } else if(on == 1) { //else if suppost to shrink shrink
      second = second + 2;
      third --;
      first --;
     } else {
      break;
     }
     printf("%s   %s   %s\n", randstring(buffer1, first), randstring(buffer2, second), randstring(buffer3, third)); //print it out
     //wait();
    }
    system("clear"); //clear screen
}
+1  A: 

I would suggest threading using pthreads and using a condition variable to sync your audio to the edge collision.

mocj
thanks for the link
austin
+1  A: 

Clearly ao_play is blocking, so you'd need a thread or forked process. I don't know the latency of forking (it's probably pretty low for your purposes), but threads are clearly a better fit.

You'd eventually want to consider mixing if new "play sound" events can overlap with the active sound's duration. Especially if overlapping sounds are possible, I'd have a dedicated fork or thread that is the only one to call ao_play, and send messages to it, rather than launching a new fork or thread each time.

wrang-wrang
that sounds right. ill go look that up. thanks.
austin
i have a question, i have pthreads working but i have no clue how i would go about sending messages between the functions... how do i accomplish that?
austin
The pthread condition variable would be your message. The audio thread will wait on it to become signaled (receive the message). The drawing thread is the one that updates it (sending a message).
mocj