Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- ** gcc -o mix mix.c -lao -lsndfile -lm
- **
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <string.h>
- #include <math.h>
- #include <ao/ao.h>
- #include <sndfile.h>
- #define BUFFSIZE 512
- int playfiles (int, FILE *[], int[]);
- int main(int argc, char *argv[])
- {
- int filesc = (argc - 1) / 2;
- FILE *fp[filesc];
- int starttime[filesc];
- if (argc < 2 || (argc - 1) % 2 != 0) {
- printf("usage: %s file1 startsec1 file2 startsec2 fileN startsecN...\n", argv[0]);
- exit(1);
- }
- for(int i=0; i < filesc; i++) {
- fp[i] = fopen(argv[i * 2 + 1], "rb");
- starttime[i] = atoi(argv[i * 2 + 2]);
- if (fp[i] == NULL) {
- printf("Cannot open %s.\n", argv[i+1]);
- exit(-1);
- }
- }
- ao_initialize ();
- playfiles (filesc, fp, starttime);
- ao_shutdown ();
- return 0;
- }
- int playfiles (int filesc, FILE *fp[], int starttime[])
- {
- int default_driver;
- ao_device *device;
- ao_sample_format format;
- SNDFILE *sndfile[filesc];
- SF_INFO sf_info[filesc];
- int startframe[filesc];
- float gain = 1.0f / filesc;
- float *filebuffer;
- float *mixbuffer;
- short *outbuffer;
- int buflen;
- int toread = 0;
- for(int i=0; i < filesc; i++) {
- sndfile[i] = sf_open_fd(fileno(fp[i]), SFM_READ, &sf_info[i], 1);
- toread += sf_info[i].frames * sf_info[i].channels;
- // convert starttime to startframe
- startframe[i] = (int) (((float) (sf_info[0].samplerate * sf_info[0].channels) / (float) BUFFSIZE) * starttime[i]);
- printf ("File %d start time %d sec, %d frame to skip\n", i, starttime[i], startframe[i]);
- }
- // all files MUST be in the same format / channels
- buflen = BUFFSIZE * sf_info[0].channels;
- filebuffer = malloc(buflen * sizeof(float));
- mixbuffer= malloc(buflen * sizeof(float));
- outbuffer= malloc(buflen * sizeof(short));
- default_driver = ao_default_driver_id();
- memset(&format, 0, sizeof(ao_sample_format));
- format.byte_format = AO_FMT_NATIVE;
- format.bits = 16;
- format.channels = sf_info[0].channels;
- format.rate = sf_info[0].samplerate;
- device = ao_open_live(default_driver, &format, NULL);
- if (device == NULL) {
- printf("Error opening sound device.\n");
- exit(-2);
- }
- while (toread > 0) {
- for(int item = 0; item < buflen; item++) {
- mixbuffer[item] = 0;
- }
- for(int i=0; i < filesc; i++) {
- if (startframe[i] == 0) {
- sf_count_t item_read = sf_read_float (sndfile[i], filebuffer, BUFFSIZE); // WHY BUFFSIZE? Shouldn't be BUFFSIZE * channels?
- if (item_read > 0) {
- toread -= item_read;
- // mix samples
- for(int item = 0; item < item_read; item++) {
- mixbuffer[item] += (filebuffer[item] * gain);
- }
- }
- } else {
- startframe[i]--;
- }
- }
- // convert from float to short
- for(int item = 0; item < buflen; item++) {
- int value = mixbuffer[item] * 32768;
- // limit to valid short values
- if (value > 32767)
- value = 32767;
- else if (value < -32768)
- value = -32768;
- outbuffer[item] = (short) value;
- }
- ao_play(device, (char *)outbuffer, buflen);
- }
- ao_close(device);
- for(int i=0; i < filesc; i++) {
- sf_close(sndfile[i]);
- }
- free(filebuffer);
- free(mixbuffer);
- free(outbuffer);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement