1 | |
2 | // Nes_Snd_Emu 0.1.7. http://www.slack.net/~ant/ |
3 | |
4 | #include "Sound_Queue.h" |
5 | |
6 | #include <assert.h> |
7 | #include <string.h> |
8 | |
9 | /* Copyright (C) 2005 by Shay Green. Permission is hereby granted, free of |
10 | charge, to any person obtaining a copy of this software module and associated |
11 | documentation files (the "Software"), to deal in the Software without |
12 | restriction, including without limitation the rights to use, copy, modify, |
13 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and |
14 | to permit persons to whom the Software is furnished to do so, subject to the |
15 | following conditions: The above copyright notice and this permission notice |
16 | shall be included in all copies or substantial portions of the Software. THE |
17 | SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
18 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A |
19 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
23 | |
24 | // Return current SDL_GetError() string, or str if SDL didn't have a string |
25 | static const char* sdl_error( const char* str ) |
26 | { |
27 | const char* sdl_str = SDL_GetError(); |
28 | if ( sdl_str && *sdl_str ) |
29 | str = sdl_str; |
30 | return str; |
31 | } |
32 | |
33 | Sound_Queue::Sound_Queue() |
34 | { |
35 | bufs = NULL; |
36 | free_sem = NULL; |
37 | write_buf = 0; |
38 | write_pos = 0; |
39 | read_buf = 0; |
40 | sound_open = false; |
41 | } |
42 | |
43 | Sound_Queue::~Sound_Queue() |
44 | { |
45 | if ( sound_open ) |
46 | { |
47 | SDL_PauseAudio( true ); |
48 | SDL_CloseAudio(); |
49 | } |
50 | |
51 | if ( free_sem ) |
52 | SDL_DestroySemaphore( free_sem ); |
53 | |
54 | delete [] bufs; |
55 | } |
56 | |
57 | int Sound_Queue::sample_count() const |
58 | { |
59 | int buf_free = SDL_SemValue( free_sem ) * buf_size + (buf_size - write_pos); |
60 | return buf_size * buf_count - buf_free; |
61 | } |
62 | |
63 | const char* Sound_Queue::init( long sample_rate, int chan_count ) |
64 | { |
65 | assert( !bufs ); // can only be initialized once |
66 | |
67 | bufs = new sample_t [(long) buf_size * buf_count]; |
68 | if ( !bufs ) |
69 | return "Out of memory" ; |
70 | |
71 | free_sem = SDL_CreateSemaphore( buf_count - 1 ); |
72 | if ( !free_sem ) |
73 | return sdl_error( "Couldn't create semaphore" ); |
74 | |
75 | SDL_AudioSpec as; |
76 | as.freq = sample_rate; |
77 | as.format = AUDIO_S16SYS; |
78 | as.channels = chan_count; |
79 | as.silence = 0; |
80 | as.samples = buf_size; |
81 | as.size = 0; |
82 | as.callback = fill_buffer_; |
83 | as.userdata = this; |
84 | if ( SDL_OpenAudio( &as, NULL ) < 0 ) |
85 | return sdl_error( "Couldn't open SDL audio" ); |
86 | SDL_PauseAudio( false ); |
87 | sound_open = true; |
88 | |
89 | return NULL; |
90 | } |
91 | |
92 | inline Sound_Queue::sample_t* Sound_Queue::buf( int index ) |
93 | { |
94 | assert( (unsigned) index < buf_count ); |
95 | return bufs + (long) index * buf_size; |
96 | } |
97 | |
98 | void Sound_Queue::write( const sample_t* in, int count ) |
99 | { |
100 | while ( count ) |
101 | { |
102 | int n = buf_size - write_pos; |
103 | if ( n > count ) |
104 | n = count; |
105 | |
106 | memcpy( buf( write_buf ) + write_pos, in, n * sizeof (sample_t) ); |
107 | in += n; |
108 | write_pos += n; |
109 | count -= n; |
110 | |
111 | if ( write_pos >= buf_size ) |
112 | { |
113 | write_pos = 0; |
114 | write_buf = (write_buf + 1) % buf_count; |
115 | SDL_SemWait( free_sem ); |
116 | } |
117 | } |
118 | } |
119 | |
120 | void Sound_Queue::fill_buffer( Uint8* out, int count ) |
121 | { |
122 | if ( SDL_SemValue( free_sem ) < buf_count - 1 ) |
123 | { |
124 | memcpy( out, buf( read_buf ), count ); |
125 | read_buf = (read_buf + 1) % buf_count; |
126 | SDL_SemPost( free_sem ); |
127 | } |
128 | else |
129 | { |
130 | memset( out, 0, count ); |
131 | } |
132 | } |
133 | |
134 | void Sound_Queue::fill_buffer_( void* user_data, Uint8* out, int count ) |
135 | { |
136 | ((Sound_Queue*) user_data)->fill_buffer( out, count ); |
137 | } |
138 | |
139 | |