Am 30.04.2015 um 10:41 schrieb [email protected]:
I've been playing around with libsndfile, libvorbisfile, libmodplug,
and libao to provide background music and sound effects for a game
engine. I have a solid handle on making one noise at a time, but I
don't understand mixing. At first I thought I would have to write my
own mixer and handle the channels, sample rate, and sample size issues
myself. I really don't want to have to do that. Then I noticed in
the libao documentation that nothing says that I cannot spawn two
threads, each of which calls ao_open_live() and ao_play() on different
sound files. Indeed, the docs for ao_initialize() seem to suggest
this can be done with the statement that it be called in the main thread.
I tried this and it works so erratically that I'm not sure libao was
written with this in mind. I get these results in order of likelihood:
1) "Segmentation fault"
2) "*** glibc detected *** ./threadtest7: malloc(): memory corruption
(fast): 0x0000000001bc5390 *** Bus error"
3) "*** glibc detected *** ./threadtest7: double free or corruption
(out):
0x00000000018ba2e0 ***"
4) A bit of the first file, then the second file.
5) Only the second file.
6) Both files messily mixed with a zipping noise. (very rare)
Is libao in fact intentionally capable of doing this? If not, what
are my options for mixing music and sound effects? I really don't
want to use SDL_mixer for a variety of reasons, chiefly because my
program is terminal-only. Virtual beer if you can guess what the
program is.
Hi
It seems libao is able to do this. Attached is the example code from the
libao side, roughly hacked in a second thread to play to signals
simultaneous. Works stable here.
regards
hermann
/*
*
* ao_example.c
*
* Written by Stan Seibert - July 2001
*
* Legal Terms:
*
* This source file is released into the public domain. It is
* distributed without any warranty; without even the implied
* warranty * of merchantability or fitness for a particular
* purpose.
*
* Function:
*
* This program opens the default driver and plays a 440 Hz tone for
* one second.
*
* Compilation command line (for Linux systems):
*
* gcc -o ao_example ao_example.c -lao -ldl -lm -lpthread
*
*/
#include <stdio.h>
#include <string.h>
#include <ao/ao.h>
#include <math.h>
#include <pthread.h>
#define BUF_SIZE 4096
/* struct to hpold info for second thread */
struct pass_ptr {
ao_device *device2;
ao_sample_format format2;
};
/* function called by second thread */
void *play2(void *play_ptr)
{
char *buffer2;
int buf_size2;
int sample2;
float freq2 = 120.0;
int i2;
struct pass_ptr *play = (struct pass_ptr*) play_ptr;
/* -- Fill buffer -- */
buf_size2 = play->format2.bits/8 * play->format2.channels * play->format2.rate;
buffer2 = calloc(buf_size2,
sizeof(char));
for (i2 = 0; i2 < play->format2.rate; i2++) {
sample2 = (int)(0.75 * 32768.0 *
sin(2 * M_PI * freq2 * ((float) i2/play->format2.rate)));
/* Put the same stuff in left and right channel */
buffer2[4*i2] = buffer2[4*i2+2] = sample2 & 0xff;
buffer2[4*i2+1] = buffer2[4*i2+3] = (sample2 >> 8) & 0xff;
}
/* play from second thread */
ao_play(play->device2, buffer2, buf_size2);
}
int main(int argc, char **argv)
{
ao_device *device;
ao_sample_format format;
int default_driver;
char *buffer;
int buf_size;
int sample;
float freq = 360.0;
int i;
int default_driver2;
pthread_t play2_thread;
struct pass_ptr play_ptr;
/* -- Initialize -- */
fprintf(stderr, "libao example program\n");
ao_initialize();
/* -- Setup for default driver -- */
default_driver = ao_default_driver_id();
memset(&format, 0, sizeof(format));
format.bits = 16;
format.channels = 2;
format.rate = 44100;
format.byte_format = AO_FMT_LITTLE;
/* -- Open first device -- */
device = ao_open_live(default_driver, &format, NULL /* no options */);
if (device == NULL) {
fprintf(stderr, "Error opening device.\n");
return 1;
}
memset(&play_ptr.format2, 0, sizeof(play_ptr.format2));
play_ptr.format2.bits = 16;
play_ptr.format2.channels = 2;
play_ptr.format2.rate = 44100;
play_ptr.format2.byte_format = AO_FMT_LITTLE;
/* -- Open second device -- */
play_ptr.device2 = ao_open_live(default_driver, &play_ptr.format2, NULL /* no options */);
if (play_ptr.device2 == NULL) {
fprintf(stderr, "Error opening device2.\n");
return 1;
}
/* create second thread to play, pass struct pointer with device and format info */
if(pthread_create(&play2_thread, NULL, play2, &play_ptr)) {
fprintf(stderr, "Error creating thread\n");
return 1;
}
/* -- Fill buffer with stuff -- */
buf_size = format.bits/8 * format.channels * format.rate;
buffer = calloc(buf_size,
sizeof(char));
for (i = 0; i < format.rate; i++) {
sample = (int)(0.75 * 32768.0 *
sin(2 * M_PI * freq * ((float) i/format.rate)));
/* Put the same stuff in left and right channel */
buffer[4*i] = buffer[4*i+2] = sample & 0xff;
buffer[4*i+1] = buffer[4*i+3] = (sample >> 8) & 0xff;
}
/* play in main thread */
ao_play(device, buffer, buf_size);
/* wait for the second thread to finish */
if(pthread_join(play2_thread, NULL)) {
fprintf(stderr, "Error joining thread\n");
return 2;
}
/* -- Close and shutdown -- */
ao_close(device);
ao_close(play_ptr.device2);
ao_shutdown();
return (0);
}
_______________________________________________
Linux-audio-dev mailing list
[email protected]
http://lists.linuxaudio.org/listinfo/linux-audio-dev