Advertisement
Guest User

Mix with libsndfile and libao

a guest
May 17th, 2016
214
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 3.66 KB | None | 0 0
  1. /*
  2. ** gcc -o mix mix.c -lao -lsndfile -lm
  3. **
  4. */
  5.  
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <stdint.h>
  9. #include <string.h>
  10. #include <math.h>
  11. #include <ao/ao.h>
  12. #include <sndfile.h>
  13.  
  14. #define BUFFSIZE 512
  15.  
  16. int playfiles (int, FILE *[], int[]);
  17.  
  18. int main(int argc, char *argv[])
  19. {
  20.     int filesc = (argc - 1) / 2;
  21.     FILE *fp[filesc];
  22.     int starttime[filesc];
  23.  
  24.     if (argc < 2 || (argc - 1) % 2 != 0) {
  25.         printf("usage: %s file1 startsec1 file2 startsec2 fileN startsecN...\n", argv[0]);
  26.         exit(1);
  27.     }
  28.     for(int i=0; i < filesc; i++) {
  29.         fp[i] = fopen(argv[i * 2 + 1], "rb");
  30.         starttime[i] = atoi(argv[i * 2 + 2]);
  31.         if (fp[i] == NULL)  {
  32.             printf("Cannot open %s.\n", argv[i+1]);
  33.             exit(-1);
  34.         }
  35.     }
  36.  
  37.     ao_initialize ();
  38.     playfiles (filesc, fp, starttime);
  39.     ao_shutdown ();
  40.  
  41.     return 0;
  42. }
  43.  
  44. int playfiles (int filesc, FILE *fp[], int starttime[])
  45. {
  46.     int default_driver;
  47.     ao_device *device;
  48.     ao_sample_format format;
  49.     SNDFILE *sndfile[filesc];
  50.     SF_INFO sf_info[filesc];
  51.     int startframe[filesc];
  52.     float gain = 1.0f / filesc;
  53.     float *filebuffer;
  54.     float *mixbuffer;
  55.     short *outbuffer;
  56.  
  57.     int buflen;
  58.     int toread = 0;
  59.  
  60.     for(int i=0; i < filesc; i++) {
  61.         sndfile[i] = sf_open_fd(fileno(fp[i]), SFM_READ, &sf_info[i], 1);
  62.         toread += sf_info[i].frames * sf_info[i].channels;
  63.         // convert starttime to startframe
  64.         startframe[i] = (int) (((float) (sf_info[0].samplerate * sf_info[0].channels) / (float) BUFFSIZE) * starttime[i]);
  65.         printf ("File %d start time %d sec, %d frame to skip\n", i, starttime[i], startframe[i]);
  66.     }
  67.  
  68.     // all files MUST be in the same format / channels
  69.     buflen = BUFFSIZE * sf_info[0].channels;
  70.     filebuffer = malloc(buflen * sizeof(float));
  71.     mixbuffer= malloc(buflen * sizeof(float));
  72.     outbuffer= malloc(buflen * sizeof(short));
  73.  
  74.     default_driver = ao_default_driver_id();
  75.     memset(&format, 0, sizeof(ao_sample_format));
  76.  
  77.     format.byte_format = AO_FMT_NATIVE;
  78.     format.bits = 16;
  79.     format.channels = sf_info[0].channels;
  80.     format.rate = sf_info[0].samplerate;
  81.  
  82.     device = ao_open_live(default_driver, &format, NULL);
  83.     if (device == NULL) {
  84.         printf("Error opening sound device.\n");
  85.         exit(-2);
  86.     }
  87.  
  88.     while (toread > 0) {
  89.         for(int item = 0; item < buflen; item++) {
  90.             mixbuffer[item] = 0;
  91.         }
  92.  
  93.         for(int i=0; i < filesc; i++) {
  94.             if (startframe[i] == 0) {
  95.                 sf_count_t item_read = sf_read_float (sndfile[i], filebuffer, BUFFSIZE); // WHY BUFFSIZE? Shouldn't be BUFFSIZE * channels?
  96.  
  97.                 if (item_read > 0) {
  98.                     toread -= item_read;
  99.  
  100.                     // mix samples
  101.                     for(int item = 0; item < item_read; item++) {
  102.                         mixbuffer[item] += (filebuffer[item] * gain);
  103.                     }
  104.                 }
  105.             } else {
  106.                 startframe[i]--;
  107.             }
  108.         }
  109.  
  110.         // convert from float to short
  111.         for(int item = 0; item < buflen; item++) {
  112.             int value = mixbuffer[item] * 32768;
  113.  
  114.             // limit to valid short values
  115.             if (value > 32767)
  116.                 value = 32767;
  117.             else if (value < -32768)
  118.                 value = -32768;
  119.  
  120.             outbuffer[item] =  (short) value;
  121.         }
  122.  
  123.         ao_play(device, (char *)outbuffer, buflen);
  124.     }
  125.  
  126.     ao_close(device);
  127.     for(int i=0; i < filesc; i++) {
  128.         sf_close(sndfile[i]);
  129.     }
  130.  
  131.     free(filebuffer);
  132.     free(mixbuffer);
  133.     free(outbuffer);
  134. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement