OpenCores
URL https://opencores.org/ocsvn/sqmusic/sqmusic/trunk

Subversion Repositories sqmusic

[/] [sqmusic/] [trunk/] [mame/] [okim6295.c] - Blame information for rev 14

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 8 gryzor
/***************************************************************************
2
 
3
    okim6295.h
4
 
5
    OKIM 6295 ADCPM sound chip.
6
 
7
****************************************************************************
8
 
9
    Library to transcode from an ADPCM source to raw PCM.
10
    Written by Buffoni Mirko in 08/06/97
11
    References: various sources and documents.
12
 
13
    R. Belmont 31/10/2003
14
    Updated to allow a driver to use both MSM6295s and "raw" ADPCM voices
15
    (gcpinbal). Also added some error trapping for MAME_DEBUG builds
16
 
17
****************************************************************************
18
 
19
    OKIM 6295 ADPCM chip:
20
 
21
    Command bytes are sent:
22
 
23
        1xxx xxxx = start of 2-byte command sequence, xxxxxxx is the sample
24
                    number to trigger
25
        abcd vvvv = second half of command; one of the abcd bits is set to
26
                    indicate which voice the v bits seem to be volumed
27
 
28
        0abc d000 = stop playing; one or more of the abcd bits is set to
29
                    indicate which voice(s)
30
 
31
    Status is read:
32
 
33
        ???? abcd = one bit per voice, set to 0 if nothing is playing, or
34
                    1 if it is active
35
 
36
***************************************************************************/
37
 
38
#include "emu.h"
39
#include "okim6295.h"
40
 
41
 
42
//**************************************************************************
43
//  GLOBAL VARIABLES
44
//**************************************************************************
45
 
46
// device type definition
47
const device_type OKIM6295 = &device_creator<okim6295_device>;
48
 
49
// volume lookup table. The manual lists only 9 steps, ~3dB per step. Given the dB values,
50
// that seems to map to a 5-bit volume control. Any volume parameter beyond the 9th index
51
// results in silent playback.
52
const UINT8 okim6295_device::s_volume_table[16] =
53
{
54
        0x20,   //   0 dB
55
        0x16,   //  -3.2 dB
56
        0x10,   //  -6.0 dB
57
        0x0b,   //  -9.2 dB
58
        0x08,   // -12.0 dB
59
        0x06,   // -14.5 dB
60
        0x04,   // -18.0 dB
61
        0x03,   // -20.5 dB
62
        0x02,   // -24.0 dB
63
        0x00,
64
        0x00,
65
        0x00,
66
        0x00,
67
        0x00,
68
        0x00,
69
        0x00,
70
};
71
 
72
// default address map
73
static ADDRESS_MAP_START( okim6295, AS_0, 8, okim6295_device )
74
        AM_RANGE(0x00000, 0x3ffff) AM_ROM
75
ADDRESS_MAP_END
76
 
77
 
78
 
79
//**************************************************************************
80
//  LIVE DEVICE
81
//**************************************************************************
82
 
83
//-------------------------------------------------
84
//  okim6295_device - constructor
85
//-------------------------------------------------
86
 
87
okim6295_device::okim6295_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
88
        : device_t(mconfig, OKIM6295, "OKI6295", tag, owner, clock),
89
                device_sound_interface(mconfig, *this),
90
                device_memory_interface(mconfig, *this),
91
                m_space_config("samples", ENDIANNESS_LITTLE, 8, 18, 0, NULL, *ADDRESS_MAP_NAME(okim6295)),
92
                m_command(-1),
93
                m_bank_installed(false),
94
                m_bank_offs(0),
95
                m_stream(NULL),
96
                m_pin7_state(0),
97
                m_direct(NULL)
98
{
99
}
100
 
101
 
102
//-------------------------------------------------
103
//  static_set_pin7 - configuration helper to set
104
//  the pin 7 state
105
//-------------------------------------------------
106
 
107
void okim6295_device::static_set_pin7(device_t &device, int pin7)
108
{
109
        okim6295_device &okim6295 = downcast<okim6295_device &>(device);
110
        okim6295.m_pin7_state = pin7;
111
}
112
 
113
 
114
//-------------------------------------------------
115
//  device_start - device-specific startup
116
//-------------------------------------------------
117
 
118
void okim6295_device::device_start()
119
{
120
        // find our direct access
121
        m_direct = &space().direct();
122
 
123
        // create the stream
124
        int divisor = m_pin7_state ? 132 : 165;
125
        m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / divisor);
126
 
127
        save_item(NAME(m_command));
128
        save_item(NAME(m_bank_offs));
129
        save_item(NAME(m_pin7_state));
130
 
131
        for (int voicenum = 0; voicenum < OKIM6295_VOICES; voicenum++)
132
        {
133
                save_item(NAME(m_voice[voicenum].m_playing), voicenum);
134
                save_item(NAME(m_voice[voicenum].m_sample), voicenum);
135
                save_item(NAME(m_voice[voicenum].m_count), voicenum);
136
                save_item(NAME(m_voice[voicenum].m_adpcm.m_signal), voicenum);
137
                save_item(NAME(m_voice[voicenum].m_adpcm.m_step), voicenum);
138
                save_item(NAME(m_voice[voicenum].m_volume), voicenum);
139
                save_item(NAME(m_voice[voicenum].m_base_offset), voicenum);
140
        }
141
}
142
 
143
 
144
//-------------------------------------------------
145
//  device_reset - device-specific reset
146
//-------------------------------------------------
147
 
148
void okim6295_device::device_reset()
149
{
150
        m_stream->update();
151
        for (int voicenum = 0; voicenum < OKIM6295_VOICES; voicenum++)
152
                m_voice[voicenum].m_playing = false;
153
}
154
 
155
 
156
//-------------------------------------------------
157
//  device_post_load - device-specific post-load
158
//-------------------------------------------------
159
 
160
void okim6295_device::device_post_load()
161
{
162
        set_bank_base(m_bank_offs, true);
163
        device_clock_changed();
164
}
165
 
166
 
167
//-------------------------------------------------
168
//  device_clock_changed - called if the clock
169
//  changes
170
//-------------------------------------------------
171
 
172
void okim6295_device::device_clock_changed()
173
{
174
        int divisor = m_pin7_state ? 132 : 165;
175
        m_stream->set_sample_rate(clock() / divisor);
176
}
177
 
178
 
179
//-------------------------------------------------
180
//  memory_space_config - return a description of
181
//  any address spaces owned by this device
182
//-------------------------------------------------
183
 
184
const address_space_config *okim6295_device::memory_space_config(address_spacenum spacenum) const
185
{
186
        return (spacenum == 0) ? &m_space_config : NULL;
187
}
188
 
189
 
190
//-------------------------------------------------
191
//  stream_generate - handle update requests for
192
//  our sound stream
193
//-------------------------------------------------
194
 
195
void okim6295_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
196
{
197
        // reset the output stream
198
        memset(outputs[0], 0, samples * sizeof(*outputs[0]));
199
 
200
        // iterate over voices and accumulate sample data
201
        for (int voicenum = 0; voicenum < OKIM6295_VOICES; voicenum++)
202
                m_voice[voicenum].generate_adpcm(*m_direct, outputs[0], samples);
203
}
204
 
205
 
206
//-------------------------------------------------
207
//  set_bank_base - old-style bank management;
208
//  assumes multiple 256k banks
209
//-------------------------------------------------
210
 
211
void okim6295_device::set_bank_base(offs_t base, bool bDontUpdateStream)
212
{
213
        // flush out anything pending (but not on e.g. a state load)
214
        if (!bDontUpdateStream)
215
        {
216
                m_stream->update();
217
        }
218
 
219
        // if we are setting a non-zero base, and we have no bank, allocate one
220
        if (!m_bank_installed && base != 0)
221
        {
222
                // override our memory map with a bank
223
                space().install_read_bank(0x00000, 0x3ffff, tag());
224
                m_bank_installed = true;
225
        }
226
 
227
        // if we have a bank number, set the base pointer
228
        if (m_bank_installed)
229
        {
230
                m_bank_offs = base;
231
                membank(tag())->set_base(m_region->base() + base);
232
        }
233
}
234
 
235
 
236
//-------------------------------------------------
237
//  set_pin7 - change the state of pin 7, which
238
//  alters the frequency we output
239
//-------------------------------------------------
240
 
241
void okim6295_device::set_pin7(int pin7)
242
{
243
        m_pin7_state = pin7;
244
        device_clock_changed();
245
}
246
 
247
 
248
//-------------------------------------------------
249
//  read_status - read the status register
250
//-------------------------------------------------
251
 
252
UINT8 okim6295_device::read_status()
253
{
254
        UINT8 result = 0xf0;    // naname expects bits 4-7 to be 1
255
 
256
        // set the bit to 1 if something is playing on a given channel
257
        m_stream->update();
258
        for (int voicenum = 0; voicenum < OKIM6295_VOICES; voicenum++)
259
                if (m_voice[voicenum].m_playing)
260
                        result |= 1 << voicenum;
261
 
262
        return result;
263
}
264
 
265
 
266
//-------------------------------------------------
267
//  read - memory interface for read
268
//-------------------------------------------------
269
 
270
READ8_MEMBER( okim6295_device::read )
271
{
272
        return read_status();
273
}
274
 
275
 
276
//-------------------------------------------------
277
//  write_command - write to the command register
278
//-------------------------------------------------
279
 
280
void okim6295_device::write_command(UINT8 command)
281
{
282
        // if a command is pending, process the second half
283
        if (m_command != -1)
284
        {
285
                // the manual explicitly says that it's not possible to start multiple voices at the same time
286
                int voicemask = command >> 4;
287
                //if (voicemask != 0 && voicemask != 1 && voicemask != 2 && voicemask != 4 && voicemask != 8)
288
                //  popmessage("OKI6295 start %x contact MAMEDEV", voicemask);
289
 
290
                // update the stream
291
                m_stream->update();
292
 
293
                // determine which voice(s) (voice is set by a 1 bit in the upper 4 bits of the second byte)
294
                for (int voicenum = 0; voicenum < OKIM6295_VOICES; voicenum++, voicemask >>= 1)
295
                        if (voicemask & 1)
296
                        {
297
                                okim_voice &voice = m_voice[voicenum];
298
 
299
                                if (!voice.m_playing) // fixes Got-cha and Steel Force
300
                                {
301
                                        // determine the start/stop positions
302
                                        offs_t base = m_command * 8;
303
 
304
                                        offs_t start = m_direct->read_raw_byte(base + 0) << 16;
305
                                        start |= m_direct->read_raw_byte(base + 1) << 8;
306
                                        start |= m_direct->read_raw_byte(base + 2) << 0;
307
                                        start &= 0x3ffff;
308
 
309
                                        offs_t stop = m_direct->read_raw_byte(base + 3) << 16;
310
                                        stop |= m_direct->read_raw_byte(base + 4) << 8;
311
                                        stop |= m_direct->read_raw_byte(base + 5) << 0;
312
                                        stop &= 0x3ffff;
313
 
314
                                        if (start < stop)
315
                                        {
316
                                                // set up the voice to play this sample
317
                                                voice.m_playing = true;
318
                                                voice.m_base_offset = start;
319
                                                voice.m_sample = 0;
320
                                                voice.m_count = 2 * (stop - start + 1);
321
 
322
                                                // also reset the ADPCM parameters
323
                                                voice.m_adpcm.reset();
324
                                                voice.m_volume = s_volume_table[command & 0x0f];
325
                                        }
326
 
327
                                        // invalid samples go here
328
                                        else
329
                                        {
330
                                                logerror("OKIM6295:'%s' requested to play invalid sample %02x\n",tag(),m_command);
331
                                        }
332
                                }
333
                                else
334
                                {
335
                                        logerror("OKIM6295:'%s' requested to play sample %02x on non-stopped voice\n",tag(),m_command);
336
                                }
337
                        }
338
 
339
                // reset the command
340
                m_command = -1;
341
        }
342
 
343
        // if this is the start of a command, remember the sample number for next time
344
        else if (command & 0x80)
345
                m_command = command & 0x7f;
346
 
347
        // otherwise, see if this is a silence command
348
        else
349
        {
350
                // update the stream, then turn it off
351
                m_stream->update();
352
 
353
                // determine which voice(s) (voice is set by a 1 bit in bits 3-6 of the command
354
                int voicemask = command >> 3;
355
                for (int voicenum = 0; voicenum < OKIM6295_VOICES; voicenum++, voicemask >>= 1)
356
                        if (voicemask & 1)
357
                                m_voice[voicenum].m_playing = false;
358
        }
359
}
360
 
361
 
362
//-------------------------------------------------
363
//  write - memory interface for write
364
//-------------------------------------------------
365
 
366
WRITE8_MEMBER( okim6295_device::write )
367
{
368
        write_command(data);
369
}
370
 
371
 
372
 
373
//**************************************************************************
374
//  OKIM VOICE
375
//**************************************************************************
376
 
377
//-------------------------------------------------
378
//  okim_voice - constructor
379
//-------------------------------------------------
380
 
381
okim6295_device::okim_voice::okim_voice()
382
        : m_playing(false),
383
                m_base_offset(0),
384
                m_sample(0),
385
                m_count(0),
386
                m_volume(0)
387
{
388
}
389
 
390
 
391
//-------------------------------------------------
392
//  generate_adpcm - generate ADPCM samples and
393
//  add them to an output stream
394
//-------------------------------------------------
395
 
396
void okim6295_device::okim_voice::generate_adpcm(direct_read_data &direct, stream_sample_t *buffer, int samples)
397
{
398
        // skip if not active
399
        if (!m_playing)
400
                return;
401
 
402
        // loop while we still have samples to generate
403
        while (samples-- != 0)
404
        {
405
                // fetch the next sample byte
406
                int nibble = direct.read_raw_byte(m_base_offset + m_sample / 2) >> (((m_sample & 1) << 2) ^ 4);
407
 
408
                // output to the buffer, scaling by the volume
409
                // signal in range -2048..2047, volume in range 2..32 => signal * volume / 2 in range -32768..32767
410
                *buffer++ += m_adpcm.clock(nibble) * m_volume / 2;
411
 
412
                // next!
413
                if (++m_sample >= m_count)
414
                {
415
                        m_playing = false;
416
                        break;
417
                }
418
        }
419
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.