Previous 199869 Revisions Next

r28770 Friday 21st March, 2014 at 00:08:34 UTC by hap
cleanup (no practical changes here except that i removed support for LOG_WAVE raw sound filewriting)
[src/emu/sound]qsound.c qsound.h

trunk/src/emu/sound/qsound.c
r28769r28770
1010
1111  QSpace position is simulated by panning the sound in the stereo space.
1212
13  Register
14  0  xxbb   xx = unknown bb = start high address
15  1  ssss   ssss = sample start address
16  2  pitch
17  3  unknown (always 0x8000)
18  4  loop offset from end address
19  5  end
20  6  master channel volume
21  7  not used
22  8  Balance (left=0x0110  centre=0x0120 right=0x0130)
23  9  unknown (most fixed samples use 0 for this register)
24
2513  Many thanks to CAB (the author of Amuse), without whom this probably would
2614  never have been finished.
2715
r28769r28770
3422#include "emu.h"
3523#include "qsound.h"
3624
37// Debug defines
38#define LOG_WAVE 0
39#define VERBOSE  0
40#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
41
42
4325// device type definition
4426const device_type QSOUND = &device_creator<qsound_device>;
4527
4628
47//**************************************************************************
48//  GLOBAL VARIABLES
49//**************************************************************************
50
5129// program map for the DSP (points to internal 4096 words of internal ROM)
5230static ADDRESS_MAP_START( dsp16_program_map, AS_PROGRAM, 16, qsound_device )
5331   AM_RANGE(0x0000, 0x0fff) AM_ROM
r28769r28770
9270      m_stream(NULL),
9371      m_sample_rom_length(0),
9472      m_sample_rom(NULL),
95      m_cpu(NULL),
96      m_frq_ratio(0.0f),
97      m_fpRawDataL(NULL),
98      m_fpRawDataR(NULL)
73      m_cpu(NULL)
9974{
10075}
10176
r28769r28770
128103
129104void qsound_device::device_start()
130105{
131   int i;
132
133106   // find our CPU
134107   m_cpu = subdevice<dsp16_device>("qsound");
135108
136   m_sample_rom = (QSOUND_SRC_SAMPLE *)*region();
109   m_sample_rom = (INT8*)*region();
137110   m_sample_rom_length = region()->bytes();
138111
139112   memset(m_channel, 0, sizeof(m_channel));
140113
141   m_frq_ratio = 16.0;
142
143114   /* Create pan table */
144   for (i=0; i<33; i++)
145   {
146      m_pan_table[i]=(int)((256/sqrt(32.0)) * sqrt((double)i));
147   }
115   for (int i = 0; i < 33; i++)
116      m_pan_table[i] = (int)((256 / sqrt(32.0)) * sqrt((double)i));
148117
149   LOG(("Pan table\n"));
150   for (i=0; i<33; i++)
151      LOG(("%02x ", m_pan_table[i]));
152
153118   /* Allocate stream */
154   m_stream = stream_alloc(0, 2, clock() / QSOUND_CLOCKDIV);
119   m_stream = stream_alloc(0, 2, clock() / 166); // /166 clock divider
155120
156   if (LOG_WAVE)
157   {
158      m_fpRawDataR=fopen("qsoundr.raw", "w+b");
159      m_fpRawDataL=fopen("qsoundl.raw", "w+b");
160   }
161
162121   /* state save */
163   for (i=0; i<QSOUND_CHANNELS; i++)
122   for (int i = 0; i < 16; i++)
164123   {
165124      save_item(NAME(m_channel[i].bank), i);
166125      save_item(NAME(m_channel[i].address), i);
167      save_item(NAME(m_channel[i].pitch), i);
126      save_item(NAME(m_channel[i].freq), i);
168127      save_item(NAME(m_channel[i].loop), i);
169128      save_item(NAME(m_channel[i].end), i);
170129      save_item(NAME(m_channel[i].vol), i);
171      save_item(NAME(m_channel[i].pan), i);
172      save_item(NAME(m_channel[i].key), i);
130      save_item(NAME(m_channel[i].enabled), i);
173131      save_item(NAME(m_channel[i].lvol), i);
174132      save_item(NAME(m_channel[i].rvol), i);
175      save_item(NAME(m_channel[i].lastdt), i);
176      save_item(NAME(m_channel[i].offset), i);
133      save_item(NAME(m_channel[i].sample), i);
134      save_item(NAME(m_channel[i].step_ptr), i);
177135   }
178136}
179137
180//-------------------------------------------------
181//  device_stop - device-specific stop
182//-------------------------------------------------
183138
184void qsound_device::device_stop()
185{
186   if (m_fpRawDataR)
187   {
188      fclose(m_fpRawDataR);
189   }
190   m_fpRawDataR = NULL;
191   if (m_fpRawDataL)
192   {
193      fclose(m_fpRawDataL);
194   }
195   m_fpRawDataL = NULL;
196}
197
198
199139//-------------------------------------------------
200140//  sound_stream_update - handle a stream update
201141//-------------------------------------------------
202142
203143void qsound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
204144{
205   int i,j;
206   int rvol, lvol, count;
207   struct QSOUND_CHANNEL *pC=&m_channel[0];
208   stream_sample_t  *datap[2];
145   // Clear the buffers
146   memset(outputs[0], 0, samples * sizeof(*outputs[0]));
147   memset(outputs[1], 0, samples * sizeof(*outputs[1]));
209148
210   datap[0] = outputs[0];
211   datap[1] = outputs[1];
212   memset( datap[0], 0x00, samples * sizeof(*datap[0]) );
213   memset( datap[1], 0x00, samples * sizeof(*datap[1]) );
214
215   for (i=0; i<QSOUND_CHANNELS; i++)
149   for (int ch = 0; ch < 16; ch++)
216150   {
217      if (pC->key)
151      if (m_channel[ch].enabled)
218152      {
219         QSOUND_SAMPLE *pOutL=datap[0];
220         QSOUND_SAMPLE *pOutR=datap[1];
221         rvol=(pC->rvol*pC->vol)>>8;
222         lvol=(pC->lvol*pC->vol)>>8;
153         stream_sample_t *lmix=outputs[0];
154         stream_sample_t *rmix=outputs[1];
155         int rvol = (m_channel[ch].rvol * m_channel[ch].vol) >> 8;
156         int lvol = (m_channel[ch].lvol * m_channel[ch].vol) >> 8;
223157
224         for (j=samples-1; j>=0; j--)
158         // Go through the buffer and add voice contributions
159         for (int i = 0; i < samples; i++)
225160         {
226            count=(pC->offset)>>16;
227            pC->offset &= 0xffff;
228            if (count)
161            if (m_channel[ch].step_ptr & ~0xfff)
229162            {
230               pC->address += count;
231               if (pC->address >= pC->end)
163               m_channel[ch].address += (m_channel[ch].step_ptr >> 12);
164               m_channel[ch].step_ptr &= 0xfff;
165               
166               if (m_channel[ch].address >= m_channel[ch].end)
232167               {
233                  if (!pC->loop)
168                  if (m_channel[ch].loop)
234169                  {
235                     /* Reached the end of a non-looped sample */
236                     pC->key=0;
170                     // Reached the end, restart the loop
171                     m_channel[ch].address = (m_channel[ch].end - m_channel[ch].loop) & 0xffff;
172                  }
173                  else
174                  {
175                     // Reached the end of a non-looped sample
176                     m_channel[ch].enabled = false;
237177                     break;
238178                  }
239                  /* Reached the end, restart the loop */
240                  pC->address = (pC->end - pC->loop) & 0xffff;
241179               }
242               pC->lastdt=m_sample_rom[(pC->bank+pC->address)%(m_sample_rom_length)];
180               m_channel[ch].sample = read_sample(m_channel[ch].bank | m_channel[ch].address);
243181            }
244182
245            (*pOutL) += ((pC->lastdt * lvol) >> 6);
246            (*pOutR) += ((pC->lastdt * rvol) >> 6);
247            pOutL++;
248            pOutR++;
249            pC->offset += pC->pitch;
183            *lmix++ += ((m_channel[ch].sample * lvol) >> 6);
184            *rmix++ += ((m_channel[ch].sample * rvol) >> 6);
185            m_channel[ch].step_ptr += m_channel[ch].freq;
250186         }
251187      }
252      pC++;
253188   }
254
255   if (m_fpRawDataL)
256      fwrite(datap[0], samples*sizeof(QSOUND_SAMPLE), 1, m_fpRawDataL);
257   if (m_fpRawDataR)
258      fwrite(datap[1], samples*sizeof(QSOUND_SAMPLE), 1, m_fpRawDataR);
259189}
260190
261191
262WRITE8_MEMBER( qsound_device::qsound_w )
192WRITE8_MEMBER(qsound_device::qsound_w)
263193{
264194   switch (offset)
265195   {
266196      case 0:
267         m_data=(m_data&0xff)|(data<<8);
197         m_data = (m_data & 0x00ff) | (data << 8);
268198         break;
269199
270200      case 1:
271         m_data=(m_data&0xff00)|data;
201         m_data = (m_data & 0xff00) | data;
272202         break;
273203
274204      case 2:
275         qsound_set_command(data, m_data);
205         write_data(data, m_data);
276206         break;
277207
278208      default:
279         logerror("%s: unexpected qsound write to offset %d == %02X\n", machine().describe_context(), offset, data);
209         logerror("%s: qsound_w %d = %02x\n", machine().describe_context(), offset, data);
280210         break;
281211   }
282212}
283213
284214
285READ8_MEMBER( qsound_device::qsound_r )
215READ8_MEMBER(qsound_device::qsound_r)
286216{
287217   /* Port ready bit (0x80 if ready) */
288218   return 0x80;
289219}
290220
291221
292void qsound_device::qsound_set_command(int data, int value)
222void qsound_device::write_data(UINT8 address, UINT16 data)
293223{
294   int ch=0,reg=0;
295   if (data < 0x80)
224   int ch = 0, reg = 0;
225
226   if (address < 0x80)
296227   {
297      ch=data>>3;
298      reg=data & 0x07;
228      ch = address >> 3;
229      reg = address & 7;
299230   }
231   else if (address < 0x90)
232   {
233      ch = address & 0xf;
234      reg = 8;
235   }
236   else if (address >= 0xba && address < 0xca)
237   {
238      ch = address - 0xba;
239      reg = 9;
240   }
300241   else
301242   {
302      if (data < 0x90)
303      {
304         ch=data-0x80;
305         reg=8;
306      }
307      else
308      {
309         if (data >= 0xba && data < 0xca)
310         {
311            ch=data-0xba;
312            reg=9;
313         }
314         else
315         {
316            /* Unknown registers */
317            ch=99;
318            reg=99;
319         }
320      }
243      // unknown
244      reg = address;
321245   }
322246
323247   switch (reg)
324248   {
325      case 0: /* Bank */
326         ch=(ch+1)&0x0f; /* strange ... */
327         m_channel[ch].bank=(value&0x7f)<<16;
328#ifdef MAME_DEBUG
329         if (!(value & 0x8000))
330            popmessage("Register3=%04x",value);
331#endif
249      case 0:
250         // bank, high bits unknown
251         ch = (ch + 1) & 0xf; // strange ...
252         m_channel[ch].bank = (data & 0x7f) << 16;
253         break;
332254
255      case 1:
256         // start/cur address
257         m_channel[ch].address = data;
333258         break;
334      case 1: /* start */
335         m_channel[ch].address=value;
336         break;
337      case 2: /* pitch */
338         m_channel[ch].pitch=value * 16;
339         if (!value)
259
260      case 2:
261         // frequency
262         m_channel[ch].freq = data;
263         if (data == 0)
340264         {
341            /* Key off */
342            m_channel[ch].key=0;
265            // key off
266            m_channel[ch].enabled = false;
343267         }
344268         break;
345      case 3: /* unknown */
346         m_channel[ch].reg3=value;
347#ifdef MAME_DEBUG
348         if (value != 0x8000)
349            popmessage("Register3=%04x",value);
350#endif
269
270      case 3:
271         // unknown, always 0x8000?
351272         break;
352      case 4: /* loop offset */
353         m_channel[ch].loop=value;
273
274      case 4:
275         // loop address
276         m_channel[ch].loop = data;
354277         break;
355      case 5: /* end */
356         m_channel[ch].end=value;
278
279      case 5:
280         // end address
281         m_channel[ch].end = data;
357282         break;
358      case 6: /* master volume */
359         if (value==0)
283
284      case 6:
285         // master volume
286         if (data == 0)
360287         {
361            /* Key off */
362            m_channel[ch].key=0;
288            // key off
289            m_channel[ch].enabled = false;
363290         }
364         else if (m_channel[ch].key==0)
291         else if (!m_channel[ch].enabled)
365292         {
366            /* Key on */
367            m_channel[ch].key=1;
368            m_channel[ch].offset=0;
369            m_channel[ch].lastdt=0;
293            // key off -> key on
294            m_channel[ch].enabled = true;
295            m_channel[ch].step_ptr = 0;
296            m_channel[ch].sample = 0;
370297         }
371         m_channel[ch].vol=value;
298         m_channel[ch].vol = data;
372299         break;
373300
374      case 7:  /* unused */
375#ifdef MAME_DEBUG
376            popmessage("UNUSED QSOUND REG 7=%04x",value);
377#endif
378
301      case 7:
302         // unused?
379303         break;
304
380305      case 8:
306      {
307         // panning (left=0x0110, centre=0x0120, right=0x0130)
308         int pandata = (data - 0x10) & 0x3f;
309         if (pandata > 32)
381310         {
382            int pandata=(value-0x10)&0x3f;
383            if (pandata > 32)
384            {
385               pandata=32;
386            }
387            m_channel[ch].rvol=m_pan_table[pandata];
388            m_channel[ch].lvol=m_pan_table[32-pandata];
389            m_channel[ch].pan = value;
311            pandata = 32;
390312         }
313         m_channel[ch].rvol = m_pan_table[pandata];
314         m_channel[ch].lvol = m_pan_table[32 - pandata];
391315         break;
392         case 9:
393         m_channel[ch].reg9=value;
394/*
395#ifdef MAME_DEBUG
396            popmessage("QSOUND REG 9=%04x",value);
397#endif
398*/
316      }
317     
318      case 9:
319         // unknown (most fixed samples use 0 for this register)
399320         break;
321
322      default:
323         //logerror("%s: write_data %02x = %04x\n", machine().describe_context(), address, data);
324         break;
400325   }
401   LOG(("QSOUND WRITE %02x CH%02d-R%02d =%04x\n", data, ch, reg, value));
402326}
trunk/src/emu/sound/qsound.h
r28769r28770
1313
1414#define QSOUND_CLOCK 4000000    /* default 4MHz clock */
1515
16#define QSOUND_CLOCKDIV 166     /* Clock divider */
17#define QSOUND_CHANNELS 16
18typedef INT8 QSOUND_SRC_SAMPLE; /* 8 bit source ROM samples */
19typedef stream_sample_t QSOUND_SAMPLE;
2016
21
2217//**************************************************************************
2318//  INTERFACE CONFIGURATION MACROS
2419//**************************************************************************
r28769r28770
2924   MCFG_DEVICE_REPLACE(_tag, QSOUND, _clock)
3025
3126
32//**************************************************************************
33//  TYPE DEFINITIONS
34//**************************************************************************
35
36struct QSOUND_CHANNEL
37{
38   INT32 bank;     // bank (x16)
39   INT32 address;  // start address
40   INT32 pitch;    // pitch
41   INT32 reg3;     // unknown (always 0x8000)
42   INT32 loop;     // loop address
43   INT32 end;      // end address
44   INT32 vol;      // master volume
45   INT32 pan;      // Pan value
46   INT32 reg9;     // unknown
47
48   /* Work variables */
49   INT32 key;      // Key on / key off
50   INT32 lvol;     // left volume
51   INT32 rvol;     // right volume
52   INT32 lastdt;   // last sample value
53   INT32 offset;   // current offset counter
54};
55
56
5727// ======================> qsound_device
5828
5929class qsound_device : public device_t,
r28769r28770
6333   qsound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
6434   ~qsound_device() { }
6535
36   DECLARE_WRITE8_MEMBER(qsound_w);
37   DECLARE_READ8_MEMBER(qsound_r);
38
6639protected:
6740   // device-level overrides
6841   const rom_entry *device_rom_region() const;
6942   machine_config_constructor device_mconfig_additions() const;
7043   virtual void device_start();
71   virtual void device_stop();
7244
7345   // sound stream update overrides
7446   virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
7547
76public:
77   DECLARE_WRITE8_MEMBER( qsound_w );
78   DECLARE_READ8_MEMBER( qsound_r );
79
8048private:
81   void qsound_set_command(int data, int value);
49   struct qsound_channel
50   {
51      UINT32 bank;        // bank
52      UINT32 address;     // start/cur address
53      UINT16 loop;        // loop address
54      UINT16 end;         // end address
55      UINT32 freq;        // frequency
56      UINT16 vol;         // master volume
8257
83private:
84   int m_data;                 // register latch data
85   sound_stream *m_stream;     // Audio stream
86   QSOUND_CHANNEL m_channel[QSOUND_CHANNELS];
58      // work variables
59      bool enabled;       // key on / key off
60      int lvol;           // left volume
61      int rvol;           // right volume
62      INT8 sample;        // last sample value
63      UINT32 step_ptr;    // current offset counter
64   } m_channel[16];
65
66   int m_pan_table[33];    // pan volume table
67   UINT16 m_data;          // register latch data
68   sound_stream *m_stream; // audio stream
8769   UINT32 m_sample_rom_length;
88   QSOUND_SRC_SAMPLE *m_sample_rom;    // Q sound sample ROM
70   INT8 *m_sample_rom;    // Q-Sound sample ROM
8971   dsp16_device *m_cpu;
9072
91   int m_pan_table[33];    // Pan volume table
92   float m_frq_ratio;      // Frequency ratio
93
94   FILE *m_fpRawDataL;
95   FILE *m_fpRawDataR;
73   inline INT8 read_sample(UINT32 offset) { return m_sample_rom[offset % m_sample_rom_length]; }
74   void write_data(UINT8 address, UINT16 data);
9675};
9776
9877extern const device_type QSOUND;

Previous 199869 Revisions Next


© 1997-2024 The MAME Team