Previous 199869 Revisions Next

r22652 Friday 3rd May, 2013 at 02:52:41 UTC by R. Belmont
(MESS) esq1: preliminary emulation of analog stages (VCFs and VCAs) [O. Galibert]

New systems added
-----------------
Ensoniq ESQ-M [Anonymous]
[src/mess]mess.lst
[src/mess/drivers]esq1.c

trunk/src/mess/drivers/esq1.c
r22651r22652
33    drivers/esq1.c
44
55    Ensoniq ESQ-1 Digital Wave Synthesizer
6    Ensoniq ESQ-M (rack-mount ESQ-1)
67    Ensoniq SQ-80 Cross Wave Synthesizer
7    Driver by R. Belmont
8    Driver by R. Belmont and O. Galibert
89
910    Map for ESQ-1 and ESQ-m:
1011    0000-1fff: OS RAM
r22651r22652
109110    35 = MODES
110111    36 = SPLIT / LAYER
111112
113
114    Analog filters (CEM3379):
115
116    The analog part is relatively simple.  The digital part outputs 8
117    voices, which are filtered, amplified, panned then summed
118    together.
119
120    The filtering stage is a 4-level lowpass filter with a loopback:
121
122
123             +-[+]-<-[*-1]--------------------------+
124             |  |                                   |
125             ^ [*r]                                 |
126             |  |                                   |
127             |  v                                   ^
128    input ---+-[+]--[LPF]---[LPF]---[LPF]---[LPF]---+--- output
129
130    All 4 LPFs are identical, with a transconductance G:
131
132    output = 1/(1+s/G)^4 * ( (1+r)*input - r*output)
133
134    or
135
136    output = input * (1+r)/((1+s/G)^4+r)
137
138    to which the usual z-transform can be applied (see votrax.c)
139
140    G is voltage controlled through the Vfreq input, with the formula (Vfreq in mV):
141
142         G = 6060*exp(Vfreq/28.5)
143
144    That gives a cutoff frequency (f=G/(2pi)) of 5Hz at 5mV, 964Hz at
145    28.5mV and 22686Hz at 90mV.  The resistor ladder between the DAC
146    and the input seem to map 0..255 into a range of -150.4mV to
147    +83.6mV.
148
149    The resonance is controlled through the Vq input pin, and is not
150    well defined.  Reading between the lines the control seems linear
151    and tops when then circuit is self-oscillation, at r=4.
152
153    The amplification is exponential for a control voltage between 0
154    to 0.2V from -100dB to -20dB, and then linear up to 5V at 0dB.  Or
155    in other words:
156         amp(Vca) = Vca < 0.2 ? 10**(-5+20*Vca) : Vca*0.1875 + 0.0625
157
158
159    Finally the panning is not very described.  What is clear is that
160    the control voltage at 2.5V gives a gain of -6dB, the max
161    attenuation at 0/5V is -100dB.  The doc also says the gain is
162    linear between 1V and 3.5V, which makes no sense since it's not
163    symmetrical, and logarithmic afterwards, probably meaning
164    exponential, otherwise the change between 0 and 1V would be
165    minimal.  So we're going to do some assumptions:
166        - 0-1V exponential from -100Db to -30dB
167        - 1V-2.5V linear from -30dB to -6dB
168        - 2.5V-5V is 1-amp at 2.5V-v
169
170    Note that this may be incorrect, maybe to sum of squares should be
171    constant, the half-point should be at -3dB and the linearity in dB
172    space.
173 
174 
112175***************************************************************************/
113176
114177#include "emu.h"
r22651r22652
124187
125188#define WD1772_TAG      "wd1772"
126189
127// QWERTYU = a few keys
128// top row 1-0 = the soft keys above and below the display (patch select)
190class esq1_filters : public device_t,
191                public device_sound_interface
192{
193public:
194   // construction/destruction
195   esq1_filters(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
129196
197   void set_vca(int channel, UINT8 value);
198   void set_vpan(int channel, UINT8 value);
199   void set_vq(int channel, UINT8 value);
200   void set_vfc(int channel, UINT8 value);
201
202protected:
203   // device-level overrides
204   virtual void device_start();
205
206   // device_sound_interface overrides
207   virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
208
209private:
210   struct filter {
211      UINT8 vca, vpan, vq, vfc;
212      double amp, lamp, ramp;
213      double a[5], b[5];
214      double x[4], y[4];
215   };
216
217   filter filters[8];
218
219   sound_stream *stream;
220
221   void recalc_filter(filter &f);
222};
223
224static const device_type ESQ1_FILTERS = &device_creator<esq1_filters>;
225
226esq1_filters::esq1_filters(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
227   : device_t(mconfig, ESQ1_FILTERS, "ESQ1 Filters stage", tag, owner, clock, "esq1-filters", __FILE__),
228     device_sound_interface(mconfig, *this)
229{
230}
231
232void esq1_filters::set_vca(int channel, UINT8 value)
233{
234   if(filters[channel].vca != value) {
235      stream->update();
236      filters[channel].vca = value;
237      recalc_filter(filters[channel]);
238   }
239}
240
241void esq1_filters::set_vpan(int channel, UINT8 value)
242{
243   if(filters[channel].vpan != value) {
244      stream->update();
245      filters[channel].vpan = value;
246      recalc_filter(filters[channel]);
247   }
248}
249
250void esq1_filters::set_vq(int channel, UINT8 value)
251{
252   if(filters[channel].vq != value) {
253      stream->update();
254      filters[channel].vq = value;
255      recalc_filter(filters[channel]);
256   }
257}
258
259void esq1_filters::set_vfc(int channel, UINT8 value)
260{
261   if(filters[channel].vfc != value) {
262      stream->update();
263      filters[channel].vfc = value;
264      recalc_filter(filters[channel]);
265   }
266}
267
268void esq1_filters::recalc_filter(filter &f)
269{
270   // Filtering stage
271   //   First let's establish the control values
272   //   Some tuning may be required
273
274   double vfc = -150.4 + (83.6+150.4)*f.vfc/255;
275   double r = 4.0*f.vq/255;
276
277
278   double g = 6060*exp(vfc/28.5);
279   double zc = g/tan(g/2/44100);
280
281/*   if(f.vfc) {
282      double ff = g/(2*M_PI);
283      double fzc = 2*M_PI*ff/tan(M_PI*ff/44100);
284      fprintf(stderr, "%02x f=%f zc=%f zc1=%f\n", f.vfc, g/(2*M_PI), zc, fzc);
285   }*/
286
287   double gzc = zc/g;
288   double gzc2 = gzc*gzc;
289   double gzc3 = gzc2*gzc;
290   double gzc4 = gzc3*gzc;
291   double r1 = 1+r;
292
293   f.a[0] = r1;
294   f.a[1] = 4*r1;
295   f.a[2] = 6*r1;
296   f.a[3] = 4*r1;
297   f.a[4] = r1;
298
299   f.b[0] =    r1 + 4*gzc + 6*gzc2 + 4*gzc3 + gzc4;
300   f.b[1] = 4*(r1 + 2*gzc          - 2*gzc3 - gzc4);
301   f.b[2] = 6*(r1         - 2*gzc2          + gzc4);
302   f.b[3] = 4*(r1 - 2*gzc          + 2*gzc3 - gzc4);
303   f.b[4] =    r1 - 4*gzc + 6*gzc2 - 4*gzc3 + gzc4;
304
305/*   if(f.vfc != 0)
306      for(int i=0; i<5; i++)
307         printf("a%d=%f\nb%d=%f\n",
308               i, f.a[i], i, f.b[i]);*/
309
310   // Amplification stage
311   double vca = f.vca*(5.0/255.0);
312   f.amp = vca < 0.2 ? pow(10, -5+20*vca) : vca*0.1875 + 0.0625;
313
314   // Panning stage
315   //   Very approximative at best
316   //   Left/right unverified
317   double vpan = f.vpan*(5.0/255.0);
318   double vref = vpan > 2.5 ? 2.5 - vpan : vpan;
319   double pan_amp = vref < 1 ? pow(10, -5+3.5*vref) : vref*0.312 - 0.280;
320   if(vref < 2.5) {
321      f.lamp = pan_amp;
322      f.ramp = 1-pan_amp;
323   } else {
324      f.lamp = 1-pan_amp;
325      f.ramp = pan_amp;
326   }
327}
328
329void esq1_filters::device_start()
330{
331   stream = stream_alloc(8, 2, 44100);
332   memset(filters, 0, sizeof(filters));
333   for(int i=0; i<8; i++)
334      recalc_filter(filters[i]);
335}
336
337void esq1_filters::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
338{
339/*   if(0) {
340      for(int i=0; i<8; i++)
341         fprintf(stderr, " [%02x %02x %02x %02x]",
342               filters[i].vca,
343               filters[i].vpan,
344               filters[i].vq,
345               filters[i].vfc);
346      fprintf(stderr, "\n");
347   }*/
348
349   for(int i=0; i<samples; i++) {
350      double l=0, r=0;
351      for(int j=0; j<8; j++) {
352         filter &f = filters[j];
353         double x = inputs[j][i];
354         double y = (x*f.a[0]
355                  + f.x[0]*f.a[1] + f.x[1]*f.a[2] + f.x[2]*f.a[3] + f.x[3]*f.a[4]
356                  - f.y[0]*f.b[1] - f.y[1]*f.b[2] - f.y[2]*f.b[3] - f.y[3]*f.b[4]) / f.b[0];
357         memmove(f.x+1, f.x, 3*sizeof(double));
358         memmove(f.y+1, f.y, 3*sizeof(double));
359         f.x[0] = x;
360         f.y[0] = y;
361         y = y * f.amp;
362         l += y * f.lamp;
363         r += y * f.ramp;
364      }
365      static double maxl = 0;
366      if(l > maxl) {
367         maxl = l;
368//         fprintf(stderr, "%f\n", maxl);
369      }
370
371//      l *= 6553;
372//      r *= 6553;
373      l *= 2;
374      r *= 2;
375      outputs[0][i] = l < -32768 ? -32768 : l > 32767 ? 32767 : int(l);
376      outputs[1][i] = r < -32768 ? -32768 : r > 32767 ? 32767 : int(r);
377   }
378}
379
130380class esq1_state : public driver_device
131381{
132382public:
r22651r22652
134384      : driver_device(mconfig, type, tag),
135385      m_maincpu(*this, "maincpu"),
136386      m_duart(*this, "duart"),
387      m_filters(*this, "filters"),
137388      m_fdc(*this, WD1772_TAG),
138389      m_panel(*this, "panel"),
139390      m_mdout(*this, "mdout")
r22651r22652
141392
142393   required_device<cpu_device> m_maincpu;
143394   required_device<duartn68681_device> m_duart;
395   required_device<esq1_filters> m_filters;
144396   optional_device<wd1772_t> m_fdc;
145397   optional_device<esqpanel2x40_device> m_panel;
146398   optional_device<serial_port_device> m_mdout;
r22651r22652
150402   DECLARE_READ8_MEMBER(seqdosram_r);
151403   DECLARE_WRITE8_MEMBER(seqdosram_w);
152404   DECLARE_WRITE8_MEMBER(mapper_w);
405   DECLARE_WRITE8_MEMBER(analog_w);
153406
154407   DECLARE_WRITE_LINE_MEMBER(duart_irq_handler);
155408   DECLARE_WRITE_LINE_MEMBER(duart_tx_a);
r22651r22652
203456//    printf("mapper_state = %d\n", data ^ 1);
204457}
205458
459WRITE8_MEMBER(esq1_state::analog_w)
460{
461   if(!(offset & 8))
462      m_filters->set_vfc(offset & 7, data);
463   if(!(offset & 16))
464      m_filters->set_vq(offset & 7, data);
465   if(!(offset & 32))
466      m_filters->set_vpan(offset & 7, data);
467   if(!(offset & 64))
468      m_filters->set_vca(offset & 7, data);
469}
470
206471READ8_MEMBER(esq1_state::seqdosram_r)
207472{
208473   if (m_mapper_state)
r22651r22652
232497   AM_RANGE(0x4000, 0x5fff) AM_RAM                 // SEQRAM
233498   AM_RANGE(0x6000, 0x63ff) AM_DEVREADWRITE("es5503", es5503_device, read, write)
234499   AM_RANGE(0x6400, 0x640f) AM_DEVREADWRITE("duart", duartn68681_device, read, write)
235   AM_RANGE(0x6800, 0x68ff) AM_NOP
236
500   AM_RANGE(0x6800, 0x68ff) AM_WRITE(analog_w)
237501   AM_RANGE(0x7000, 0x7fff) AM_ROMBANK("osbank")
238502   AM_RANGE(0x8000, 0xffff) AM_ROM AM_REGION("osrom", 0x8000)  // OS "high" ROM is always mapped here
239503ADDRESS_MAP_END
r22651r22652
244508//  AM_RANGE(0x4000, 0x5fff) AM_READWRITE(seqdosram_r, seqdosram_w)
245509   AM_RANGE(0x6000, 0x63ff) AM_DEVREADWRITE("es5503", es5503_device, read, write)
246510   AM_RANGE(0x6400, 0x640f) AM_DEVREADWRITE("duart", duartn68681_device, read, write)
511   AM_RANGE(0x6800, 0x68ff) AM_WRITE(analog_w)
247512   AM_RANGE(0x6c00, 0x6dff) AM_WRITE(mapper_w)
248513   AM_RANGE(0x6e00, 0x6fff) AM_READWRITE(wd1772_r, wd1772_w)
249514   AM_RANGE(0x7000, 0x7fff) AM_ROMBANK("osbank")
r22651r22652
267532
268533WRITE_LINE_MEMBER(esq1_state::duart_irq_handler)
269534{
270   m_maincpu->set_input_line(0, state);
535    m_maincpu->set_input_line(M6809_IRQ_LINE, state);
271536};
272537
273538READ8_MEMBER(esq1_state::duart_input)
r22651r22652
290555// MIDI send
291556WRITE_LINE_MEMBER(esq1_state::duart_tx_a)
292557{
293   m_mdout->tx(state);
558    m_mdout->tx(state);
294559}
295560
296561WRITE_LINE_MEMBER(esq1_state::duart_tx_b)
297562{
298   m_panel->rx_w(state);
563    m_panel->rx_w(state);
299564}
300565
301566void esq1_state::send_through_panel(UINT8 data)
302567{
303   m_panel->xmit_char(data);
568    m_panel->xmit_char(data);
304569}
305570
306571INPUT_CHANGED_MEMBER(esq1_state::key_stroke)
307572{
308   if (oldval == 0 && newval == 1)
309   {
310      send_through_panel((UINT8)(FPTR)param);
311      send_through_panel((UINT8)(FPTR)0x00);
312   }
313   else if (oldval == 1 && newval == 0)
314   {
315      send_through_panel((UINT8)(FPTR)param&0x7f);
316      send_through_panel((UINT8)(FPTR)0x00);
317   }
573    if (oldval == 0 && newval == 1)
574    {
575       send_through_panel((UINT8)(FPTR)param);
576       send_through_panel((UINT8)(FPTR)0x00);
577    }
578    else if (oldval == 1 && newval == 0)
579    {
580       send_through_panel((UINT8)(FPTR)param&0x7f);
581       send_through_panel((UINT8)(FPTR)0x00);
582    }
318583}
319584
320585static SLOT_INTERFACE_START(midiin_slot)
r22651r22652
362627   MCFG_SERIAL_PORT_ADD("mdout", midiout_intf, midiout_slot, "midiout", NULL)
363628
364629   MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
365   MCFG_ES5503_ADD("es5503", 7000000, 8, esq1_doc_irq, esq1_adc_read)
630
631   MCFG_SOUND_ADD("filters", ESQ1_FILTERS, 0)
366632   MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
367633   MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
368   MCFG_SOUND_ROUTE(2, "lspeaker", 1.0)
369   MCFG_SOUND_ROUTE(3, "rspeaker", 1.0)
370   MCFG_SOUND_ROUTE(4, "lspeaker", 1.0)
371   MCFG_SOUND_ROUTE(5, "rspeaker", 1.0)
372   MCFG_SOUND_ROUTE(6, "lspeaker", 1.0)
373   MCFG_SOUND_ROUTE(7, "rspeaker", 1.0)
634
635   MCFG_ES5503_ADD("es5503", 7000000, 8, esq1_doc_irq, esq1_adc_read)
636   MCFG_SOUND_ROUTE_EX(0, "filters", 1.0, 0)
637   MCFG_SOUND_ROUTE_EX(1, "filters", 1.0, 1)
638   MCFG_SOUND_ROUTE_EX(2, "filters", 1.0, 2)
639   MCFG_SOUND_ROUTE_EX(3, "filters", 1.0, 3)
640   MCFG_SOUND_ROUTE_EX(4, "filters", 1.0, 4)
641   MCFG_SOUND_ROUTE_EX(5, "filters", 1.0, 5)
642   MCFG_SOUND_ROUTE_EX(6, "filters", 1.0, 6)
643   MCFG_SOUND_ROUTE_EX(7, "filters", 1.0, 7)
374644MACHINE_CONFIG_END
375645
376646static MACHINE_CONFIG_DERIVED(sq80, esq1)
r22651r22652
435705   ROM_LOAD( "sq80_kpc_150.bin", 0x000000, 0x008000, CRC(8170b728) SHA1(3ad68bb03948e51b20d2e54309baa5c02a468f7c) )
436706ROM_END
437707
708ROM_START( esqm )
709   ROM_REGION(0x10000, "osrom", 0)
710        ROM_LOAD( "1355500157_d640_esq-m_oshi.u14", 0x8000, 0x008000, CRC(ea6a7bae) SHA1(2830f8c52dc443b4ca469dc190b33e2ff15b78e1) )
711
712   ROM_REGION(0x20000, "es5503", 0)
713   ROM_LOAD( "esq1wavlo.bin", 0x0000, 0x8000, CRC(4d04ac87) SHA1(867b51229b0a82c886bf3b216aa8893748236d8b) )
714   ROM_LOAD( "esq1wavhi.bin", 0x8000, 0x8000, CRC(94c554a3) SHA1(ed0318e5253637585559e8cf24c06d6115bd18f6) )
715ROM_END
716
717
438718CONS( 1986, esq1, 0   , 0, esq1, esq1, driver_device, 0, "Ensoniq", "ESQ-1", GAME_NOT_WORKING )
719CONS( 1986, esqm, esq1, 0, esq1, esq1, driver_device, 0, "Ensoniq", "ESQ-M", GAME_NOT_WORKING )
439720CONS( 1988, sq80, 0,    0, sq80, esq1, driver_device, 0, "Ensoniq", "SQ-80", GAME_NOT_WORKING )
721
trunk/src/mess/mess.lst
r22651r22652
164164// Ensoniq
165165enmirage    // 1985 Mirage Digital Multi-Sampler
166166esq1        // 1986 ESQ-1 Digital Wave Synthesizer
167esqm        // 1986 ESQ-M rack-mount ESQ-1
167168sq80        // 1988 SQ-80 Digital Wave Synthesizer
168169eps         // 1988 EPS
169170vfx         // 1989 VFX

Previous 199869 Revisions Next


© 1997-2024 The MAME Team