I've tried to use the Allegro sound recording routines and I've come to the conclusion that that the DirectX ones don't do what the documentation says they do.
My original post was http://www.allegro.cc/forums/view_thread.php?_id=459212
Then I wasn't sure if I was doing it right, but now I think it's a bug. Recording is one of the few parts of Allegro without an example. Does anyone have an example program for recording which has worked for them?
I can't test the code myself, but I just looked at the source in src/win/wdsinput.c. It seems to have some frequencies hardcoded, maybe try checking if the frequency is valid, or try with one of the frequencies in there..
[edit]
And I wouldn't be surprised if it is actually broken. But then I doubt any of the current main developers will be able to fix it - so someone who knows about DSound will have to find the bug in the mentioned source file.
I just wrote a working example. It's not good enough to be an official example, but it should get the idea across.
You should call read_sound_input only when needed. To do this, check the size of the input buffer and calculate how many milliseconds will be needed to fill it. While testing it, I got a buffer large enough to hold one second of data.
The code below uses 9/10th of that interval to determine when to call it.
I recommand that we change the documentation accordingly. Instead of:
You must be sure to call this function at regular intervals during the recording (typically around 100 times a second), or some data will be lost.
The documentation should read:
"You must be sure to call this function at regular intervals during the recording, or some data will be lost. To determine the maximum interval, check the size returned by start_sound_input() and determine the time needed to fill this buffer. Use a value that is slightly lower than this maximum period, 50%-90% of the maximum work fine."
| 1 | #include <allegro.h> |
| 2 | #include <stdio.h> |
| 3 | #include <string.h> |
| 4 | |
| 5 | int main(void) { |
| 6 | |
| 7 | int ofs = 0; |
| 8 | int len; |
| 9 | int size; |
| 10 | int foo; |
| 11 | int rate = 44100; |
| 12 | int result = 0; |
| 13 | SAMPLE *sample; |
| 14 | int interval; |
| 15 | unsigned char*buf; |
| 16 | |
| 17 | allegro_init(); |
| 18 | install_timer(); |
| 19 | install_keyboard(); |
| 20 | install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL); |
| 21 | |
| 22 | install_sound_input(DIGI_AUTODETECT, MIDI_NONE); |
| 23 | result = get_sound_input_cap_parm(rate, 16, 0); |
| 24 | set_volume(255,255); |
| 25 | |
| 26 | if (result < 0) { |
| 27 | rate = result *-1; |
| 28 | } else if (rate == 0) { |
| 29 | exit(0); |
| 30 | } |
| 31 | printf("rate = %i\n", rate); |
| 32 | size = 1024*1024; |
| 33 | sample = create_sample(16, 0, rate, size); |
| 34 | buf = sample->data; |
| 35 | |
| 36 | |
| 37 | set_sound_input_source(1); |
| 38 | len = start_sound_input(rate, 16, 0); |
| 39 | |
| 40 | /* calc max interval */ |
| 41 | interval = 1000 / ((len / 2) / rate); |
| 42 | |
| 43 | /* use 9/10 of the max intervall */ |
| 44 | interval *= 9; |
| 45 | interval /= 10; |
| 46 | |
| 47 | printf("len=%i, intervall=%i\n", len, interval); |
| 48 | while (!keypressed() && ofs < size) { |
| 49 | foo = read_sound_input(buf); |
| 50 | if (foo > 0) { |
| 51 | ofs += len; |
| 52 | buf += len; |
| 53 | printf("%i\n", foo); |
| 54 | } |
| 55 | rest(interval); |
| 56 | } |
| 57 | if (keypressed()) { |
| 58 | foo = read_sound_input(buf); |
| 59 | if (foo > 0) { |
| 60 | ofs += len; |
| 61 | buf += len; |
| 62 | printf("%i\n", foo); |
| 63 | } |
| 64 | } |
| 65 | stop_sound_input(); |
| 66 | clear_keybuf(); |
| 67 | |
| 68 | play_sample(sample, 255, 128, 1000,0); |
| 69 | |
| 70 | while (!key[KEY_ESC]); |
| 71 | |
| 72 | } |
| 73 | END_OF_MAIN() |
Thanks spellcaster, your example worked. Something like it should be added to the Allegro examples.
I still need to look into it more to see what the effective difference is with mine. In my program I was calling read_sound_input all the time, assuming it would only return non-zero at the appropriate time. It was returning non-zero more often than it was supposed to, giving me buffers which were similar to each other.
i use PortAudio lib.
it works great on windows for audio recording.
i think its cross platform too.
still need to look into it more to see what the effective difference is with mine. In my program I was calling read_sound_input all the time, assuming it would only return non-zero at the appropriate time. It was returning non-zero more often than it was supposed to, giving me buffers which were similar to each other.
I did that at first as well (since it was suggested in the docs), and the results are horrible. I guess read_sound_input does something that disturbs the recording slightly. The more often you call it the more problems you'll get.
I'd need to check the DSound routines and the allegro implementation to see how one could improve that.
My example should not be added to allegro right now. The code is a mess because I tried lot's of stuff before it worked. The example should also be able to deal with several formats and confirm that these formats actually work, etc.