~ubuntu-branches/debian/sid/mame/sid

« back to all changes in this revision

Viewing changes to src/mame/audio/flower.c

  • Committer: Package Import Robot
  • Author(s): Jordi Mallach, Jordi Mallach, Emmanuel Kasper
  • Date: 2011-12-19 22:56:27 UTC
  • mfrom: (0.1.2)
  • Revision ID: package-import@ubuntu.com-20111219225627-ub5oga1oys4ogqzm
Tags: 0.144-1
[ Jordi Mallach ]
* Fix syntax errors in DEP5 copyright file (lintian).
* Use a versioned copyright Format specification field.
* Update Vcs-* URLs.
* Move transitional packages to the new metapackages section, and make
  them priority extra.
* Remove references to GNU/Linux and MESS sources from copyright.
* Add build variables for s390x.
* Use .xz tarballs as it cuts 4MB for the upstream sources.
* Add nplayers.ini as a patch. Update copyright file to add CC-BY-SA-3.0.

[ Emmanuel Kasper ]
* New upstream release. Closes: #651538.
* Add Free Desktop compliant png icons of various sizes taken from
  the hydroxygen iconset
* Mess is now built from a new source package, to avoid possible source
  incompatibilities between mame and the mess overlay.
* Mame-tools are not built from the mame source package anymore, but
  from the mess source package

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***************************************************************************
2
 
 
3
 
    Flower sound driver (quick hack of the Wiping sound driver)
4
 
 
5
 
***************************************************************************/
 
1
/* Clarue Flower sound driver.
 
2
Initial version was based on the Wiping sound driver, which was based on the old namco.c sound driver.
 
3
 
 
4
TODO:
 
5
- timing (see main driver file), but also of samplerate and effects counter
 
6
- what do the unknown bits in soundregs do?
 
7
- Are channel effects correct? It's currently mostly guesswork, the pitch effects sound pretty convincing though.
 
8
  Considering that the game sound hardware isn't complicated (no dedicated soundchip) these bits are possibly
 
9
  for something way simpler, such as a length counter. PCB sound recordings would be useful!
 
10
 
 
11
*/
6
12
 
7
13
#include "emu.h"
8
14
#include "includes/flower.h"
9
15
 
10
 
 
11
 
/* 8 voices max */
12
 
#define MAX_VOICES 8
13
 
 
14
 
 
15
 
static const int samplerate = 48000;
16
 
static const int defgain = 48;
 
16
#define FLOWER_VERBOSE          0               // show register writes
 
17
 
 
18
#define MIXER_SAMPLERATE        48000   /* ? (native freq is probably in the MHz range) */
 
19
#define MIXER_DEFGAIN           48
17
20
 
18
21
 
19
22
/* this structure defines the parameters for a channel */
20
23
typedef struct
21
24
{
22
 
        UINT32 frequency;
23
 
        UINT32 counter;
24
 
        UINT16 volume;
 
25
        UINT32 start;
 
26
        UINT32 pos;
 
27
        UINT16 freq;
 
28
        UINT8 volume;
 
29
        UINT8 voltab;
25
30
        UINT8 oneshot;
26
 
        UINT8 oneshotplaying;
27
 
        UINT16 rom_offset;
 
31
        UINT8 active;
 
32
        UINT8 effect;
 
33
        UINT32 ecount;
28
34
 
29
35
} sound_channel;
30
36
 
32
38
typedef struct _flower_sound_state flower_sound_state;
33
39
struct _flower_sound_state
34
40
{
 
41
        emu_timer *m_effect_timer;
 
42
 
35
43
        /* data about the sound system */
36
 
        sound_channel m_channel_list[MAX_VOICES];
 
44
        sound_channel m_channel_list[8];
37
45
        sound_channel *m_last_channel;
38
46
 
39
47
        /* global sound parameters */
40
 
        const UINT8 *m_sound_rom1;
41
 
        const UINT8 *m_sound_rom2;
42
 
        UINT8 m_num_voices;
43
 
        UINT8 m_sound_enable;
 
48
        const UINT8 *m_sample_rom;
 
49
        const UINT8 *m_volume_rom;
44
50
        sound_stream * m_stream;
45
51
 
46
52
        /* mixer tables and internal buffers */
47
53
        INT16 *m_mixer_table;
48
54
        INT16 *m_mixer_lookup;
49
55
        short *m_mixer_buffer;
50
 
        short *m_mixer_buffer_2;
51
56
 
52
57
        UINT8 m_soundregs1[0x40];
53
58
        UINT8 m_soundregs2[0x40];
80
85
                int val = i * gain * 16 / voices;
81
86
                if (val > 32767) val = 32767;
82
87
                state->m_mixer_lookup[ i] = val;
83
 
                state->m_mixer_lookup[-i] = -val;
 
88
                state->m_mixer_lookup[-i] =-val;
84
89
        }
85
90
}
86
91
 
94
99
        short *mix;
95
100
        int i;
96
101
 
97
 
        /* if no sound, we're done */
98
 
        if (state->m_sound_enable == 0)
99
 
        {
100
 
                memset(buffer, 0, samples * sizeof(*buffer));
101
 
                return;
102
 
        }
103
 
 
104
102
        /* zap the contents of the mixer buffer */
105
103
        memset(state->m_mixer_buffer, 0, samples * sizeof(short));
106
104
 
107
105
        /* loop over each voice and add its contribution */
108
106
        for (voice = state->m_channel_list; voice < state->m_last_channel; voice++)
109
107
        {
110
 
                int f = 256*voice->frequency;
 
108
                int f = voice->freq;
111
109
                int v = voice->volume;
112
110
 
113
 
                /* only update if we have non-zero volume and frequency */
114
 
                if (v && f)
115
 
                {
116
 
                        const UINT8 *w = &state->m_sound_rom1[voice->rom_offset];
117
 
                        int c = voice->counter;
118
 
 
119
 
                        mix = state->m_mixer_buffer;
120
 
 
121
 
                        /* add our contribution */
122
 
                        for (i = 0; i < samples; i++)
 
111
                if (!voice->active)
 
112
                        continue;
 
113
 
 
114
                // effects
 
115
                // bit 0: volume slide down?
 
116
                if (voice->effect & 1 && !voice->oneshot)
 
117
                {
 
118
                        // note: one-shot samples are fixed volume
 
119
                        v -= (voice->ecount >> 4);
 
120
                        if (v < 0) v = 0;
 
121
                }
 
122
                // bit 1: used often, but hard to figure out what for
 
123
                // bit 2: probably pitch slide
 
124
                if (voice->effect & 4)
 
125
                {
 
126
                        f -= (voice->ecount << 7);
 
127
                        if (f < 0) f = 0;
 
128
                }
 
129
                // bit 3: not used much, maybe pitch slide the other way?
 
130
 
 
131
                v |= voice->voltab;
 
132
                mix = state->m_mixer_buffer;
 
133
 
 
134
                for (i = 0; i < samples; i++)
 
135
                {
 
136
                        // add sample
 
137
                        if (voice->oneshot)
123
138
                        {
124
 
                                int offs;
125
 
 
126
 
                                c += f;
127
 
 
128
 
                                if (voice->oneshot)
 
139
                                UINT8 sample = state->m_sample_rom[(voice->start + voice->pos) >> 7 & 0x7fff];
 
140
                                if (sample == 0xff)
129
141
                                {
130
 
                                        if (voice->oneshotplaying)
131
 
                                        {
132
 
                                                offs = (c >> 15);
133
 
                                                if (w[offs] == 0xff)
134
 
                                                {
135
 
                                                        voice->oneshotplaying = 0;
136
 
                                                }
137
 
 
138
 
                                                else
139
 
                                                {
140
 
//                          *mix++ += ((w[offs] - 0x80) * v) / 16;
141
 
                                                        *mix++ += state->m_sound_rom2[v*256 + w[offs]] - 0x80;
142
 
                                                }
143
 
                                        }
 
142
                                        voice->active = 0;
 
143
                                        break;
144
144
                                }
145
145
                                else
146
 
                                {
147
 
                                        offs = (c >> 15) & 0x1ff;
148
 
 
149
 
//                  *mix++ += ((w[offs] - 0x80) * v) / 16;
150
 
                                        *mix++ += state->m_sound_rom2[v*256 + w[offs]] - 0x80;
151
 
                                }
152
 
                        }
153
 
 
154
 
                        /* update the counter for this voice */
155
 
                        voice->counter = c;
 
146
                                        *mix++ += state->m_volume_rom[v << 8 | sample] - 0x80;
 
147
                        }
 
148
                        else
 
149
                        {
 
150
                                UINT8 sample = state->m_sample_rom[(voice->start >> 7 & 0x7e00) | (voice->pos >> 7 & 0x1ff)];
 
151
                                *mix++ += state->m_volume_rom[v << 8 | sample] - 0x80;
 
152
                        }
 
153
 
 
154
                        // update counter
 
155
                        voice->pos += f;
156
156
                }
157
157
        }
158
158
 
162
162
                *buffer++ = state->m_mixer_lookup[*mix++];
163
163
}
164
164
 
 
165
/* clock sound channel effect counters */
 
166
static TIMER_CALLBACK( flower_clock_effect )
 
167
{
 
168
        flower_sound_state *state = (flower_sound_state *)ptr;
 
169
        sound_channel *voice;
 
170
        state->m_stream->update();
 
171
 
 
172
        for (voice = state->m_channel_list; voice < state->m_last_channel; voice++)
 
173
                voice->ecount += (voice->ecount < (1<<22));
 
174
}
 
175
 
165
176
 
166
177
 
167
178
static DEVICE_START( flower_sound )
171
182
        sound_channel *voice;
172
183
        int i;
173
184
 
174
 
        /* get stream channels */
175
 
        state->m_stream = device->machine().sound().stream_alloc(*device, 0, 1, samplerate, 0, flower_update_mono);
176
 
 
177
 
        /* allocate a pair of buffers to mix into - 1 second's worth should be more than enough */
178
 
        state->m_mixer_buffer = auto_alloc_array(device->machine(), short, 2 * samplerate);
179
 
        state->m_mixer_buffer_2 = state->m_mixer_buffer + samplerate;
180
 
 
181
 
        /* build the mixer table */
182
 
        make_mixer_table(device, 8, defgain);
 
185
        state->m_effect_timer = machine.scheduler().timer_alloc(FUNC(flower_clock_effect), state);
 
186
        state->m_stream = device->machine().sound().stream_alloc(*device, 0, 1, MIXER_SAMPLERATE, 0, flower_update_mono);
 
187
        state->m_mixer_buffer = auto_alloc_array(device->machine(), short, MIXER_SAMPLERATE);
 
188
        make_mixer_table(device, 8, MIXER_DEFGAIN);
183
189
 
184
190
        /* extract globals from the interface */
185
 
        state->m_num_voices = 8;
186
 
        state->m_last_channel = state->m_channel_list + state->m_num_voices;
187
 
 
188
 
        state->m_sound_rom1 = machine.region("sound1")->base();
189
 
        state->m_sound_rom2 = machine.region("sound2")->base();
190
 
 
191
 
        /* start with sound enabled, many games don't have a sound enable register */
192
 
        state->m_sound_enable = 1;
193
 
 
194
 
        /* save globals */
195
 
        device->save_item(NAME(state->m_num_voices));
196
 
        device->save_item(NAME(state->m_sound_enable));
 
191
        state->m_last_channel = state->m_channel_list + 8;
 
192
 
 
193
        state->m_sample_rom = machine.region("sound1")->base();
 
194
        state->m_volume_rom = machine.region("sound2")->base();
 
195
 
 
196
        /* register for savestates */
 
197
        for (i = 0; i < 8; i++)
 
198
        {
 
199
                voice = &state->m_channel_list[i];
 
200
 
 
201
                device->save_item(NAME(voice->freq), i+1);
 
202
                device->save_item(NAME(voice->pos), i+1);
 
203
                device->save_item(NAME(voice->volume), i+1);
 
204
                device->save_item(NAME(voice->voltab), i+1);
 
205
                device->save_item(NAME(voice->effect), i+1);
 
206
                device->save_item(NAME(voice->ecount), i+1);
 
207
                device->save_item(NAME(voice->oneshot), i+1);
 
208
                device->save_item(NAME(voice->active), i+1);
 
209
                device->save_item(NAME(voice->start), i+1);
 
210
        }
 
211
}
 
212
 
 
213
static DEVICE_RESET( flower_sound )
 
214
{
 
215
        flower_sound_state *state = get_safe_token(device);
 
216
        sound_channel *voice;
 
217
        attotime period;
 
218
        int i;
 
219
 
 
220
        /* reset effect timer, period is unknown/guessed */
 
221
        period = attotime::from_hz(MIXER_SAMPLERATE / 256);
 
222
        state->m_effect_timer->adjust(period, 0, period);
197
223
 
198
224
        /* reset all the voices */
199
 
        for (i = 0; i < state->m_num_voices; i++)
 
225
        for (i = 0; i < 8; i++)
200
226
        {
201
227
                voice = &state->m_channel_list[i];
202
228
 
203
 
                voice->frequency = 0;
 
229
                voice->freq = 0;
 
230
                voice->pos = 0;
204
231
                voice->volume = 0;
205
 
                voice->counter = 0;
206
 
                voice->rom_offset = 0;
207
 
 
208
 
                device->save_item(NAME(voice->frequency), i+1);
209
 
                device->save_item(NAME(voice->counter), i+1);
210
 
                device->save_item(NAME(voice->volume), i+1);
211
 
                device->save_item(NAME(voice->oneshot), i+1);
212
 
                device->save_item(NAME(voice->oneshotplaying), i+1);
213
 
                device->save_item(NAME(voice->rom_offset), i+1);
 
232
                voice->voltab = 0;
 
233
                voice->effect = 0;
 
234
                voice->ecount = 0;
 
235
                voice->oneshot = 1;
 
236
                voice->active = 0;
 
237
                voice->start = 0;
214
238
        }
215
239
}
216
240
 
217
 
 
218
241
DEVICE_GET_INFO( flower_sound )
219
242
{
220
243
        switch (state)
224
247
 
225
248
                /* --- the following bits of info are returned as pointers to data or functions --- */
226
249
                case DEVINFO_FCT_START:                                                 info->start = DEVICE_START_NAME(flower_sound);  break;
 
250
                case DEVINFO_FCT_RESET:                                                 info->start = DEVICE_RESET_NAME(flower_sound);  break;
227
251
 
228
252
                /* --- the following bits of info are returned as NULL-terminated strings --- */
229
253
                case DEVINFO_STR_NAME:                                                  strcpy(info->s, "Flower Custom");                               break;
230
254
                case DEVINFO_STR_SOURCE_FILE:                                   strcpy(info->s, __FILE__);                                              break;
 
255
                case DEVINFO_STR_CREDITS:                                               strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
231
256
        }
232
257
}
233
258
 
234
259
 
235
260
/********************************************************************************/
236
261
 
 
262
#if FLOWER_VERBOSE
 
263
static int r_numwrites[2][8] = {{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}};
 
264
static void show_soundregs(device_t *device)
 
265
{
 
266
        flower_sound_state *state = get_safe_token(device);
 
267
        int set,reg,chan;
 
268
        char text[0x100];
 
269
        char message[0x1000] = {0};
 
270
        UINT8 *base = state->m_soundregs1;
 
271
 
 
272
        for (set=0;set<2;set++)
 
273
        {
 
274
                for (reg=0;reg<8;reg++)
 
275
                {
 
276
                        sprintf(text,"R%d%d:",set+1,reg);
 
277
                        strcat(message,text);
 
278
 
 
279
                        for (chan=0;chan<8;chan++)
 
280
                        {
 
281
                                sprintf(text," %02X",base[reg + 8*chan]);
 
282
                                strcat(message,text);
 
283
                        }
 
284
                        sprintf(text," - %07d\n",r_numwrites[set][reg]);
 
285
                        strcat(message,text);
 
286
                }
 
287
                strcat(message,"\n");
 
288
                base = state->m_soundregs2;
 
289
        }
 
290
        popmessage("%s",message);
 
291
}
 
292
#endif // FLOWER_VERBOSE
 
293
 
 
294
 
 
295
/* register functions (preliminary):
 
296
offset: cccrrr      c=channel, r=register
 
297
 
 
298
set 1:
 
299
R  76543210
 
300
0  xxxxxxxx         frequency (which nibble?)
 
301
1  xxxxxxxx         *
 
302
2  xxxxxxxx         *
 
303
3  xxxxxxxx         *
 
304
4  ...x....         one-shot sample
 
305
5  ...x....         ??? same as R4?
 
306
6  ........         unused
 
307
7  xxxx....         volume
 
308
 
 
309
set 2:
 
310
R  76543210
 
311
0  ....xxxx         start address
 
312
1  ....xxxx         *
 
313
2  ....xxxx         *
 
314
3  ....xxxx         *
 
315
4  xxxx             assume it's channel pitch/volume effects
 
316
       xxxx         start address
 
317
5  x...             ???
 
318
       xxxx         start address
 
319
6  ........         unused
 
320
7  ......xx         volume table + start trigger
 
321
 
 
322
*/
 
323
 
237
324
WRITE8_DEVICE_HANDLER( flower_sound1_w )
238
325
{
239
326
        flower_sound_state *state = get_safe_token(device);
240
 
        sound_channel *voice;
241
 
        int base;
 
327
        sound_channel *voice = &state->m_channel_list[offset >> 3 & 7];
 
328
        int c = offset & 0xf8;
 
329
        UINT8 *base1 = state->m_soundregs1;
 
330
//  UINT8 *base2 = state->m_soundregs2;
242
331
 
243
 
        /* update the streams */
244
332
        state->m_stream->update();
245
 
 
246
 
        /* set the register */
247
 
        state->m_soundregs1[offset] = data;
248
 
 
249
 
        /* recompute all the voice parameters */
250
 
        for (base = 0, voice = state->m_channel_list; voice < state->m_last_channel; voice++, base += 8)
251
 
        {
252
 
                voice->frequency = state->m_soundregs1[2 + base] & 0x0f;
253
 
                voice->frequency = voice->frequency * 16 + ((state->m_soundregs1[3 + base]) & 0x0f);
254
 
                voice->frequency = voice->frequency * 16 + ((state->m_soundregs1[0 + base]) & 0x0f);
255
 
                voice->frequency = voice->frequency * 16 + ((state->m_soundregs1[1 + base]) & 0x0f);
256
 
 
257
 
                voice->volume = (state->m_soundregs1[7 + base] >> 4) | ((state->m_soundregs2[7 + base] & 0x03) << 4);
258
 
// the following would fix the hanging notes...
259
 
//if ((state->m_soundregs2[7 + base] & 0x01) == 0)
260
 
//  voice->volume = 0;
261
 
 
262
 
                if (state->m_soundregs1[4 + base] & 0x10)
263
 
                {
264
 
                        voice->oneshot = 0;
265
 
                        voice->oneshotplaying = 0;
266
 
                }
267
 
                else
268
 
                {
269
 
                        voice->oneshot = 1;
270
 
                }
271
 
        }
 
333
        base1[offset] = data;
 
334
#if FLOWER_VERBOSE
 
335
        r_numwrites[0][offset & 7]++;
 
336
        show_soundregs(device);
 
337
#endif
 
338
 
 
339
        // recompute voice parameters
 
340
        voice->freq = (base1[c+2] & 0xf) << 12 | (base1[c+3] & 0xf) << 8 | (base1[c+0] & 0xf) << 4 | (base1[c+1] & 0xf);
 
341
        voice->volume = base1[c+7] >> 4;
272
342
}
273
343
 
274
344
WRITE8_DEVICE_HANDLER( flower_sound2_w )
275
345
{
276
346
        flower_sound_state *state = get_safe_token(device);
277
 
        sound_channel *voice;
278
 
        int base = offset & 0xf8;
279
 
 
280
 
/*
281
 
popmessage("%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x",
282
 
        state->m_soundregs2[7 + 8*0],state->m_soundregs1[7 + 8*0],
283
 
        state->m_soundregs2[7 + 8*1],state->m_soundregs1[7 + 8*1],
284
 
        state->m_soundregs2[7 + 8*2],state->m_soundregs1[7 + 8*2],
285
 
        state->m_soundregs2[7 + 8*3],state->m_soundregs1[7 + 8*3],
286
 
        state->m_soundregs2[7 + 8*4],state->m_soundregs1[7 + 8*4],
287
 
        state->m_soundregs2[7 + 8*5],state->m_soundregs1[7 + 8*5],
288
 
        state->m_soundregs2[7 + 8*6],state->m_soundregs1[7 + 8*6],
289
 
        state->m_soundregs2[7 + 8*7],state->m_soundregs1[7 + 8*7]
290
 
    );
291
 
*/
292
 
 
293
 
        /* update the streams */
 
347
        sound_channel *voice = &state->m_channel_list[offset >> 3 & 7];
 
348
        int i, c = offset & 0xf8;
 
349
        UINT8 *base1 = state->m_soundregs1;
 
350
        UINT8 *base2 = state->m_soundregs2;
 
351
 
294
352
        state->m_stream->update();
295
 
 
296
 
        /* set the register */
297
 
        state->m_soundregs2[offset] = data;
298
 
 
299
 
        /* recompute all the voice parameters */
300
 
        voice = &state->m_channel_list[offset/8];
301
 
        if (voice->oneshot)
302
 
        {
303
 
                int start;
304
 
 
305
 
                start = state->m_soundregs2[5 + base] & 0x0f;
306
 
                start = start * 16 + ((state->m_soundregs2[4 + base]) & 0x0f);
307
 
                start = start * 16 + ((state->m_soundregs2[3 + base]) & 0x0f);
308
 
                start = start * 16 + ((state->m_soundregs2[2 + base]) & 0x0f);
309
 
                start = start * 16 + ((state->m_soundregs2[1 + base]) & 0x0f);
310
 
                start = start * 16 + ((state->m_soundregs2[0 + base]) & 0x0f);
311
 
 
312
 
                voice->rom_offset = (start >> 7) & 0x7fff;
313
 
 
314
 
                voice->counter = 0;
315
 
                voice->oneshotplaying = 1;
316
 
        }
317
 
        else
318
 
        {
319
 
                int start;
320
 
 
321
 
                start = state->m_soundregs2[5 + base] & 0x0f;
322
 
                start = start * 16 + ((state->m_soundregs2[4 + base]) & 0x0f);
323
 
 
324
 
                voice->rom_offset = (start << 9) & 0x7fff;      // ???
325
 
                voice->oneshot = 0;
326
 
                voice->oneshotplaying = 0;
327
 
        }
 
353
        base2[offset] = data;
 
354
#if FLOWER_VERBOSE
 
355
        r_numwrites[1][offset & 7]++;
 
356
        show_soundregs(device);
 
357
#endif
 
358
 
 
359
        // reg 7 is start trigger!
 
360
        if ((offset & 7) != 7)
 
361
                return;
 
362
 
 
363
        voice->voltab = (base2[c+7] & 3) << 4;
 
364
        voice->oneshot = (~base1[c+4] & 0x10) >> 4;
 
365
        voice->effect = base2[c+4] >> 4;
 
366
        voice->ecount = 0;
 
367
        voice->pos = 0;
 
368
        voice->active = 1;
 
369
 
 
370
        // full start address is 6 nibbles
 
371
        voice->start = 0;
 
372
        for (i = 5; i >= 0; i--)
 
373
                voice->start = (voice->start << 4) | (base2[c+i] & 0xf);
328
374
}
329
375
 
330
376