~ubuntu-branches/debian/stretch/opentyrian/stretch

« back to all changes in this revision

Viewing changes to src/loudness.c

  • Committer: Package Import Robot
  • Author(s): Etienne Millon
  • Date: 2015-03-31 08:48:54 UTC
  • Revision ID: package-import@ubuntu.com-20150331084854-f5a4uoz7uv3vopk6
Tags: upstream-2.1.20130907+dfsg
ImportĀ upstreamĀ versionĀ 2.1.20130907+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * OpenTyrian: A modern cross-platform port of Tyrian
 
3
 * Copyright (C) 2007-2009  The OpenTyrian Development Team
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * as published by the Free Software Foundation; either version 2
 
8
 * of the License, or (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
18
 */
 
19
#include "file.h"
 
20
#include "lds_play.h"
 
21
#include "loudness.h"
 
22
#include "nortsong.h"
 
23
#include "opentyr.h"
 
24
#include "params.h"
 
25
 
 
26
float music_volume = 0, sample_volume = 0;
 
27
 
 
28
bool music_stopped = true;
 
29
unsigned int song_playing = 0;
 
30
 
 
31
bool audio_disabled = false, music_disabled = false, samples_disabled = false;
 
32
 
 
33
/* SYN: These shouldn't be used outside this file. Hands off! */
 
34
FILE *music_file = NULL;
 
35
Uint32 *song_offset;
 
36
Uint16 song_count = 0;
 
37
 
 
38
 
 
39
SAMPLE_TYPE *channel_buffer[SFX_CHANNELS] = { NULL };
 
40
SAMPLE_TYPE *channel_pos[SFX_CHANNELS] = { NULL };
 
41
Uint32 channel_len[SFX_CHANNELS] = { 0 };
 
42
Uint8 channel_vol[SFX_CHANNELS];
 
43
 
 
44
int sound_init_state = false;
 
45
int freq = 11025 * OUTPUT_QUALITY;
 
46
 
 
47
static SDL_AudioCVT audio_cvt; // used for format conversion
 
48
 
 
49
void audio_cb( void *userdata, unsigned char *feedme, int howmuch );
 
50
 
 
51
void load_song( unsigned int song_num );
 
52
 
 
53
bool init_audio( void )
 
54
{
 
55
        if (audio_disabled)
 
56
                return false;
 
57
        
 
58
        SDL_AudioSpec ask, got;
 
59
        
 
60
        ask.freq = freq;
 
61
        ask.format = (BYTES_PER_SAMPLE == 2) ? AUDIO_S16SYS : AUDIO_S8;
 
62
        ask.channels = 1;
 
63
        ask.samples = 2048;
 
64
        ask.callback = audio_cb;
 
65
        
 
66
        printf("\trequested %d Hz, %d channels, %d samples\n", ask.freq, ask.channels, ask.samples);
 
67
        
 
68
        if (SDL_OpenAudio(&ask, &got) == -1)
 
69
        {
 
70
                fprintf(stderr, "error: failed to initialize SDL audio: %s\n", SDL_GetError());
 
71
                audio_disabled = true;
 
72
                return false;
 
73
        }
 
74
        
 
75
        printf("\tobtained  %d Hz, %d channels, %d samples\n", got.freq, got.channels, got.samples);
 
76
        
 
77
        SDL_BuildAudioCVT(&audio_cvt, ask.format, ask.channels, ask.freq, got.format, got.channels, got.freq);
 
78
        
 
79
        opl_init();
 
80
        
 
81
        SDL_PauseAudio(0); // unpause
 
82
        
 
83
        return true;
 
84
}
 
85
 
 
86
void audio_cb( void *user_data, unsigned char *sdl_buffer, int howmuch )
 
87
{
 
88
        (void)user_data;
 
89
        
 
90
        // prepare for conversion
 
91
        howmuch /= audio_cvt.len_mult;
 
92
        audio_cvt.buf = sdl_buffer;
 
93
        audio_cvt.len = howmuch;
 
94
        
 
95
        static long ct = 0;
 
96
        
 
97
        SAMPLE_TYPE *feedme = (SAMPLE_TYPE *)sdl_buffer;
 
98
 
 
99
        if (!music_disabled && !music_stopped)
 
100
        {
 
101
                /* SYN: Simulate the fm synth chip */
 
102
                SAMPLE_TYPE *music_pos = feedme;
 
103
                long remaining = howmuch / BYTES_PER_SAMPLE;
 
104
                while (remaining > 0)
 
105
                {
 
106
                        while (ct < 0)
 
107
                        {
 
108
                                ct += freq;
 
109
                                lds_update(); /* SYN: Do I need to use the return value for anything here? */
 
110
                        }
 
111
                        /* SYN: Okay, about the calculations below. I still don't 100% get what's going on, but...
 
112
                        - freq is samples/time as output by SDL.
 
113
                        - REFRESH is how often the play proc would have been called in Tyrian. Standard speed is
 
114
                        70Hz, which is the default value of 70.0f
 
115
                        - ct represents the margin between play time (representing # of samples) and tick speed of
 
116
                        the songs (70Hz by default). It keeps track of which one is ahead, because they don't
 
117
                        synch perfectly. */
 
118
                        
 
119
                        /* set i to smaller of data requested by SDL and a value calculated from the refresh rate */
 
120
                        long i = (long)((ct / REFRESH) + 4) & ~3;
 
121
                        i = (i > remaining) ? remaining : i; /* i should now equal the number of samples we get */
 
122
                        opl_update((SAMPLE_TYPE *)music_pos, i);
 
123
                        music_pos += i;
 
124
                        remaining -= i;
 
125
                        ct -= (long)(REFRESH * i);
 
126
                }
 
127
                
 
128
                /* Reduce the music volume. */
 
129
                int qu = howmuch / BYTES_PER_SAMPLE;
 
130
                for (int smp = 0; smp < qu; smp++)
 
131
                {
 
132
                        feedme[smp] *= music_volume;
 
133
                }
 
134
        }
 
135
        
 
136
        if (!samples_disabled)
 
137
        {
 
138
                /* SYN: Mix sound channels and shove into audio buffer */
 
139
                for (int ch = 0; ch < SFX_CHANNELS; ch++)
 
140
                {
 
141
                        float volume = sample_volume * (channel_vol[ch] / (float)SFX_CHANNELS);
 
142
                        
 
143
                        /* SYN: Don't copy more data than is in the channel! */
 
144
                        unsigned int qu = ((unsigned)howmuch > channel_len[ch] ? channel_len[ch] : (unsigned)howmuch) / BYTES_PER_SAMPLE;
 
145
                        for (unsigned int smp = 0; smp < qu; smp++)
 
146
                        {
 
147
#if (BYTES_PER_SAMPLE == 2)
 
148
                                Sint32 clip = (Sint32)feedme[smp] + (Sint32)(channel_pos[ch][smp] * volume);
 
149
                                feedme[smp] = (clip > 0x7fff) ? 0x7fff : (clip <= -0x8000) ? -0x8000 : (Sint16)clip;
 
150
#else  /* BYTES_PER_SAMPLE */
 
151
                                Sint16 clip = (Sint16)feedme[smp] + (Sint16)(channel_pos[ch][smp] * volume);
 
152
                                feedme[smp] = (clip > 0x7f) ? 0x7f : (clip <= -0x80) ? -0x80 : (Sint8)clip;
 
153
#endif  /* BYTES_PER_SAMPLE */
 
154
                        }
 
155
                        
 
156
                        channel_pos[ch] += qu;
 
157
                        channel_len[ch] -= qu * BYTES_PER_SAMPLE;
 
158
                        
 
159
                        /* SYN: If we've emptied a channel buffer, let's free the memory and clear the channel. */
 
160
                        if (channel_len[ch] == 0)
 
161
                        {
 
162
                                free(channel_buffer[ch]);
 
163
                                channel_buffer[ch] = channel_pos[ch] = NULL;
 
164
                        }
 
165
                }
 
166
        }
 
167
        
 
168
        // do conversion
 
169
        SDL_ConvertAudio(&audio_cvt);
 
170
}
 
171
 
 
172
void deinit_audio( void )
 
173
{
 
174
        if (audio_disabled)
 
175
                return;
 
176
        
 
177
        SDL_PauseAudio(1); // pause
 
178
        
 
179
        SDL_CloseAudio();
 
180
        
 
181
        for (unsigned int i = 0; i < SFX_CHANNELS; i++)
 
182
        {
 
183
                free(channel_buffer[i]);
 
184
                channel_buffer[i] = channel_pos[i] = NULL;
 
185
                channel_len[i] = 0;
 
186
        }
 
187
        
 
188
        lds_free();
 
189
}
 
190
 
 
191
 
 
192
void load_music( void )
 
193
{
 
194
        if (music_file == NULL)
 
195
        {
 
196
                music_file = dir_fopen_die(data_dir(), "music.mus", "rb");
 
197
                
 
198
                efread(&song_count, sizeof(song_count), 1, music_file);
 
199
                
 
200
                song_offset = malloc((song_count + 1) * sizeof(*song_offset));
 
201
                
 
202
                efread(song_offset, 4, song_count, music_file);
 
203
                song_offset[song_count] = ftell_eof(music_file);
 
204
        }
 
205
}
 
206
 
 
207
void load_song( unsigned int song_num )
 
208
{
 
209
        if (audio_disabled)
 
210
                return;
 
211
        
 
212
        SDL_LockAudio();
 
213
        
 
214
        if (song_num < song_count)
 
215
        {
 
216
                unsigned int song_size = song_offset[song_num + 1] - song_offset[song_num];
 
217
                lds_load(music_file, song_offset[song_num], song_size);
 
218
        }
 
219
        else
 
220
        {
 
221
                fprintf(stderr, "warning: failed to load song %d\n", song_num + 1);
 
222
        }
 
223
        
 
224
        SDL_UnlockAudio();
 
225
}
 
226
 
 
227
void play_song( unsigned int song_num )
 
228
{
 
229
        if (song_num != song_playing)
 
230
        {
 
231
                load_song(song_num);
 
232
                song_playing = song_num;
 
233
        }
 
234
        
 
235
        music_stopped = false;
 
236
}
 
237
 
 
238
void restart_song( void )
 
239
{
 
240
        unsigned int temp = song_playing;
 
241
        song_playing = -1;
 
242
        play_song(temp);
 
243
}
 
244
 
 
245
void stop_song( void )
 
246
{
 
247
        music_stopped = true;
 
248
}
 
249
 
 
250
void fade_song( void )
 
251
{
 
252
        /* STUB: we have no implementation of this to port */
 
253
}
 
254
 
 
255
void set_volume( unsigned int music, unsigned int sample )
 
256
{
 
257
        music_volume = music * (1.5f / 255.0f);
 
258
        sample_volume = sample * (1.0f / 255.0f);
 
259
}
 
260
 
 
261
void JE_multiSamplePlay(JE_byte *buffer, JE_word size, JE_byte chan, JE_byte vol)
 
262
{
 
263
        if (audio_disabled || samples_disabled)
 
264
                return;
 
265
        
 
266
        SDL_LockAudio();
 
267
        
 
268
        free(channel_buffer[chan]);
 
269
        
 
270
        channel_len[chan] = size * BYTES_PER_SAMPLE * SAMPLE_SCALING;
 
271
        channel_buffer[chan] = malloc(channel_len[chan]);
 
272
        channel_pos[chan] = channel_buffer[chan];
 
273
        channel_vol[chan] = vol + 1;
 
274
 
 
275
        for (int i = 0; i < size; i++)
 
276
        {
 
277
                for (int ex = 0; ex < SAMPLE_SCALING; ex++)
 
278
                {
 
279
#if (BYTES_PER_SAMPLE == 2)
 
280
                        channel_buffer[chan][(i * SAMPLE_SCALING) + ex] = (Sint8)buffer[i] << 8;
 
281
#else  /* BYTES_PER_SAMPLE */
 
282
                        channel_buffer[chan][(i * SAMPLE_SCALING) + ex] = (Sint8)buffer[i];
 
283
#endif  /* BYTES_PER_SAMPLE */
 
284
                }
 
285
        }
 
286
 
 
287
        SDL_UnlockAudio();
 
288
}
 
289