DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/mame/ymdeltat.cpp
00001 // license:GPL-2.0+
00002 // copyright-holders:Jarek Burczynski
00003 /*
00004 **
00005 ** File: ymdeltat.c
00006 **
00007 ** YAMAHA DELTA-T adpcm sound emulation subroutine
00008 ** used by fmopl.c (Y8950) and fm.c (YM2608 and YM2610/B)
00009 **
00010 ** Base program is YM2610 emulator by Hiromitsu Shioya.
00011 ** Written by Tatsuyuki Satoh
00012 ** Improvements by Jarek Burczynski (bujar at mame dot net)
00013 **
00014 **
00015 ** History:
00016 **
00017 ** 03-08-2003 Jarek Burczynski:
00018 **  - fixed BRDY flag implementation.
00019 **
00020 ** 24-07-2003 Jarek Burczynski, Frits Hilderink:
00021 **  - fixed delault value for control2 in YM_DELTAT_ADPCM_Reset
00022 **
00023 ** 22-07-2003 Jarek Burczynski, Frits Hilderink:
00024 **  - fixed external memory support
00025 **
00026 ** 15-06-2003 Jarek Burczynski:
00027 **  - implemented CPU -> AUDIO ADPCM synthesis (via writes to the ADPCM data reg $08)
00028 **  - implemented support for the Limit address register
00029 **  - supported two bits from the control register 2 ($01): RAM TYPE (x1 bit/x8 bit), ROM/RAM
00030 **  - implemented external memory access (read/write) via the ADPCM data reg reads/writes
00031 **    Thanks go to Frits Hilderink for the example code.
00032 **
00033 ** 14-06-2003 Jarek Burczynski:
00034 **  - various fixes to enable proper support for status register flags: BSRDY, PCM BSY, ZERO
00035 **  - modified EOS handling
00036 **
00037 ** 05-04-2003 Jarek Burczynski:
00038 **  - implemented partial support for external/processor memory on sample replay
00039 **
00040 ** 01-12-2002 Jarek Burczynski:
00041 **  - fixed first missing sound in gigandes thanks to previous fix (interpolator) by ElSemi
00042 **  - renamed/removed some YM_DELTAT struct fields
00043 **
00044 ** 28-12-2001 Acho A. Tang
00045 **  - added EOS status report on ADPCM playback.
00046 **
00047 ** 05-08-2001 Jarek Burczynski:
00048 **  - now_step is initialized with 0 at the start of play.
00049 **
00050 ** 12-06-2001 Jarek Burczynski:
00051 **  - corrected end of sample bug in YM_DELTAT_ADPCM_CALC.
00052 **    Checked on real YM2610 chip - address register is 24 bits wide.
00053 **    Thanks go to Stefan Jokisch (stefan.jokisch@gmx.de) for tracking down the problem.
00054 **
00055 ** TO DO:
00056 **      Check size of the address register on the other chips....
00057 **
00058 ** Version 0.72
00059 **
00060 ** sound chips that have this unit:
00061 ** YM2608   OPNA
00062 ** YM2610/B OPNB
00063 ** Y8950    MSX AUDIO
00064 **
00065 */
00066 
00067 #include "emu.h"
00068 #include "ymdeltat.h"
00069 
00070 #define YM_DELTAT_SHIFT    (16)
00071 
00072 #define YM_DELTAT_DELTA_MAX (24576)
00073 #define YM_DELTAT_DELTA_MIN (127)
00074 #define YM_DELTAT_DELTA_DEF (127)
00075 
00076 #define YM_DELTAT_DECODE_RANGE 32768
00077 #define YM_DELTAT_DECODE_MIN (-(YM_DELTAT_DECODE_RANGE))
00078 #define YM_DELTAT_DECODE_MAX ((YM_DELTAT_DECODE_RANGE)-1)
00079 
00080 
00081 /* Forecast to next Forecast (rate = *8) */
00082 /* 1/8 , 3/8 , 5/8 , 7/8 , 9/8 , 11/8 , 13/8 , 15/8 */
00083 static const int32_t ym_deltat_decode_tableB1[16] = {
00084         1,   3,   5,   7,   9,  11,  13,  15,
00085         -1,  -3,  -5,  -7,  -9, -11, -13, -15,
00086 };
00087 /* delta to next delta (rate= *64) */
00088 /* 0.9 , 0.9 , 0.9 , 0.9 , 1.2 , 1.6 , 2.0 , 2.4 */
00089 static const int32_t ym_deltat_decode_tableB2[16] = {
00090         57,  57,  57,  57, 77, 102, 128, 153,
00091         57,  57,  57,  57, 77, 102, 128, 153
00092 };
00093 
00094 #if 0
00095 void YM_DELTAT::BRDY_callback()
00096 {
00097         logerror("BRDY_callback reached (flag set) !\n");
00098 
00099         /* set BRDY bit in status register */
00100         if(status_set_handler)
00101                 if(status_change_BRDY_bit)
00102                         (status_set_handler)(status_change_which_chip, status_change_BRDY_bit);
00103 }
00104 #endif
00105 
00106 uint8_t YM_DELTAT::ADPCM_Read()
00107 {
00108         uint8_t v = 0;
00109 
00110         /* external memory read */
00111         if ((portstate & 0xe0) == 0x20)
00112         {
00113                 /* two dummy reads */
00114                 if (memread)
00115                 {
00116                         now_addr = start << 1;
00117                         memread--;
00118                         return 0;
00119                 }
00120 
00121 
00122                 if (now_addr != (end << 1))
00123                 {
00124                         v = memory[now_addr>>1];
00125 
00126                         /*logerror("YM Delta-T memory read  $%08x, v=$%02x\n", now_addr >> 1, v);*/
00127 
00128                         now_addr += 2; /* two nibbles at a time */
00129 
00130                         /* reset BRDY bit in status register, which means we are reading the memory now */
00131                         if (status_reset_handler && status_change_BRDY_bit)
00132                                 (status_reset_handler)(status_change_which_chip, status_change_BRDY_bit);
00133 
00134                         /* setup a timer that will callback us in 10 master clock cycles for Y8950
00135                         * in the callback set the BRDY flag to 1 , which means we have another data ready.
00136                         * For now, we don't really do this; we simply reset and set the flag in zero time, so that the IRQ will work.
00137                         */
00138                         /* set BRDY bit in status register */
00139                         if (status_set_handler && status_change_BRDY_bit)
00140                                 (status_set_handler)(status_change_which_chip, status_change_BRDY_bit);
00141                 }
00142                 else
00143                 {
00144                         /* set EOS bit in status register */
00145                         if (status_set_handler && status_change_EOS_bit)
00146                                 (status_set_handler)(status_change_which_chip, status_change_EOS_bit);
00147                 }
00148         }
00149 
00150         return v;
00151 }
00152 
00153 
00154 /* 0-DRAM x1, 1-ROM, 2-DRAM x8, 3-ROM (3 is bad setting - not allowed by the manual) */
00155 static const uint8_t dram_rightshift[4]={3,0,0,0};
00156 
00157 /* DELTA-T ADPCM write register */
00158 void YM_DELTAT::ADPCM_Write(int r, int v)
00159 {
00160         if (r >= 0x10) return;
00161         reg[r] = v; /* stock data */
00162 
00163         switch (r)
00164         {
00165         case 0x00:
00166 /*
00167 START:
00168     Accessing *external* memory is started when START bit (D7) is set to "1", so
00169     you must set all conditions needed for recording/playback before starting.
00170     If you access *CPU-managed* memory, recording/playback starts after
00171     read/write of ADPCM data register $08.
00172 
00173 REC:
00174     0 = ADPCM synthesis (playback)
00175     1 = ADPCM analysis (record)
00176 
00177 MEMDATA:
00178     0 = processor (*CPU-managed*) memory (means: using register $08)
00179     1 = external memory (using start/end/limit registers to access memory: RAM or ROM)
00180 
00181 
00182 SPOFF:
00183     controls output pin that should disable the speaker while ADPCM analysis
00184 
00185 RESET and REPEAT only work with external memory.
00186 
00187 
00188 some examples:
00189 value:   START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET   meaning:
00190   C8     1      1    0       0       1      0 0 0       Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register
00191   E8     1      1    1       0       1      0 0 0       Analysis (recording) from AUDIO to EXT.MEMORY,       sample rate in PRESCALER register
00192   80     1      0    0       0       0      0 0 0       Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register
00193   a0     1      0    1       0       0      0 0 0       Synthesis (playing) from EXT.MEMORY to AUDIO,        sample rate in DELTA-N register
00194 
00195   60     0      1    1       0       0      0 0 0       External memory write via ADPCM data register $08
00196   20     0      0    1       0       0      0 0 0       External memory read via ADPCM data register $08
00197 
00198 */
00199                 /* handle emulation mode */
00200                 if (emulation_mode == EMULATION_MODE_YM2610)
00201                 {
00202                         v |= 0x20;      /*  YM2610 always uses external memory and doesn't even have memory flag bit. */
00203                 }
00204 
00205                 portstate = v & (0x80|0x40|0x20|0x10|0x01); /* start, rec, memory mode, repeat flag copy, reset(bit0) */
00206 
00207                 if (portstate & 0x80)/* START,REC,MEMDATA,REPEAT,SPOFF,--,--,RESET */
00208                 {
00209                         /* set PCM BUSY bit */
00210                         PCM_BSY = 1;
00211 
00212                         /* start ADPCM */
00213                         now_step = 0;
00214                         acc      = 0;
00215                         prev_acc = 0;
00216                         adpcml   = 0;
00217                         adpcmd   = YM_DELTAT_DELTA_DEF;
00218                         now_data = 0;
00219 
00220                 }
00221 
00222                 if (portstate & 0x20) /* do we access external memory? */
00223                 {
00224                         now_addr = start << 1;
00225                         memread = 2;    /* two dummy reads needed before accesing external memory via register $08*/
00226 
00227                         /* if yes, then let's check if ADPCM memory is mapped and big enough */
00228                         if (!memory)
00229                         {
00230                                 device->logerror("YM Delta-T ADPCM rom not mapped\n");
00231                                 portstate = 0x00;
00232                                 PCM_BSY = 0;
00233                         }
00234                         else
00235                         {
00236                                 if (end >= memory_size)    /* Check End in Range */
00237                                 {
00238                                         device->logerror("YM Delta-T ADPCM end out of range: $%08x\n", end);
00239                                         end = memory_size - 1;
00240                                 }
00241                                 if (start >= memory_size)  /* Check Start in Range */
00242                                 {
00243                                         device->logerror("YM Delta-T ADPCM start out of range: $%08x\n", start);
00244                                         portstate = 0x00;
00245                                         PCM_BSY = 0;
00246                                 }
00247                         }
00248                 }
00249                 else    /* we access CPU memory (ADPCM data register $08) so we only reset now_addr here */
00250                 {
00251                         now_addr = 0;
00252                 }
00253 
00254                 if (portstate & 0x01)
00255                 {
00256                         portstate = 0x00;
00257 
00258                         /* clear PCM BUSY bit (in status register) */
00259                         PCM_BSY = 0;
00260 
00261                         /* set BRDY flag */
00262                         if (status_set_handler && status_change_BRDY_bit)
00263                                 (status_set_handler)(status_change_which_chip, status_change_BRDY_bit);
00264                 }
00265                 break;
00266 
00267         case 0x01:  /* L,R,-,-,SAMPLE,DA/AD,RAMTYPE,ROM */
00268                 /* handle emulation mode */
00269                 if (emulation_mode == EMULATION_MODE_YM2610)
00270                 {
00271                         v |= 0x01;      /*  YM2610 always uses ROM as an external memory and doesn't tave ROM/RAM memory flag bit. */
00272                 }
00273 
00274                 pan = &output_pointer[(v >> 6) & 0x03];
00275                 if ((control2 & 3) != (v & 3))
00276                 {
00277                         /*0-DRAM x1, 1-ROM, 2-DRAM x8, 3-ROM (3 is bad setting - not allowed by the manual) */
00278                         if (DRAMportshift != dram_rightshift[v & 3])
00279                         {
00280                                 DRAMportshift = dram_rightshift[v & 3];
00281 
00282                                 /* final shift value depends on chip type and memory type selected:
00283                                         8 for YM2610 (ROM only),
00284                                         5 for ROM for Y8950 and YM2608,
00285                                         5 for x8bit DRAMs for Y8950 and YM2608,
00286                                         2 for x1bit DRAMs for Y8950 and YM2608.
00287                                 */
00288 
00289                                 /* refresh addresses */
00290                                 start  = (reg[0x3] * 0x0100 | reg[0x2]) << (portshift - DRAMportshift);
00291                                 end    = (reg[0x5] * 0x0100 | reg[0x4]) << (portshift - DRAMportshift);
00292                                 end   += (1 << (portshift - DRAMportshift)) - 1;
00293                                 limit  = (reg[0xd]*0x0100 | reg[0xc]) << (portshift - DRAMportshift);
00294                         }
00295                 }
00296                 control2 = v;
00297                 break;
00298 
00299         case 0x02:  /* Start Address L */
00300         case 0x03:  /* Start Address H */
00301                 start  = (reg[0x3] * 0x0100 | reg[0x2]) << (portshift - DRAMportshift);
00302                 /*logerror("DELTAT start: 02=%2x 03=%2x addr=%8x\n",reg[0x2], reg[0x3],start );*/
00303                 break;
00304 
00305         case 0x04:  /* Stop Address L */
00306         case 0x05:  /* Stop Address H */
00307                 end    = (reg[0x5]*0x0100 | reg[0x4]) << (portshift - DRAMportshift);
00308                 end   += (1 << (portshift - DRAMportshift)) - 1;
00309                 /*logerror("DELTAT end  : 04=%2x 05=%2x addr=%8x\n",reg[0x4], reg[0x5],end   );*/
00310                 break;
00311 
00312         case 0x06:  /* Prescale L (ADPCM and Record frq) */
00313         case 0x07:  /* Prescale H */
00314                 break;
00315 
00316         case 0x08:  /* ADPCM data */
00317 /*
00318 some examples:
00319 value:   START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET   meaning:
00320   C8     1      1    0       0       1      0 0 0       Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register
00321   E8     1      1    1       0       1      0 0 0       Analysis (recording) from AUDIO to EXT.MEMORY,       sample rate in PRESCALER register
00322   80     1      0    0       0       0      0 0 0       Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register
00323   a0     1      0    1       0       0      0 0 0       Synthesis (playing) from EXT.MEMORY to AUDIO,        sample rate in DELTA-N register
00324 
00325   60     0      1    1       0       0      0 0 0       External memory write via ADPCM data register $08
00326   20     0      0    1       0       0      0 0 0       External memory read via ADPCM data register $08
00327 
00328 */
00329 
00330                 /* external memory write */
00331                 if ((portstate & 0xe0) == 0x60)
00332                 {
00333                         if (memread)
00334                         {
00335                                 now_addr = start << 1;
00336                                 memread = 0;
00337                         }
00338 
00339                         /*logerror("YM Delta-T memory write $%08x, v=$%02x\n", now_addr >> 1, v);*/
00340 
00341                         if (now_addr != (end << 1))
00342                         {
00343                                 memory[now_addr >> 1] = v;
00344                                 now_addr += 2; /* two nybbles at a time */
00345 
00346                                 /* reset BRDY bit in status register, which means we are processing the write */
00347                                 if (status_reset_handler && status_change_BRDY_bit)
00348                                         (status_reset_handler)(status_change_which_chip, status_change_BRDY_bit);
00349 
00350                                 /* setup a timer that will callback us in 10 master clock cycles for Y8950
00351                                 * in the callback set the BRDY flag to 1 , which means we have written the data.
00352                                 * For now, we don't really do this; we simply reset and set the flag in zero time, so that the IRQ will work.
00353                                 */
00354                                 /* set BRDY bit in status register */
00355                                 if (status_set_handler && status_change_BRDY_bit)
00356                                         (status_set_handler)(status_change_which_chip, status_change_BRDY_bit);
00357 
00358                         }
00359                         else
00360                         {
00361                                 /* set EOS bit in status register */
00362                                 if (status_set_handler && status_change_EOS_bit)
00363                                         (status_set_handler)(status_change_which_chip, status_change_EOS_bit);
00364                         }
00365 
00366                         return;
00367                 }
00368 
00369                 /* ADPCM synthesis from CPU */
00370                 if ((portstate & 0xe0) == 0x80)
00371                 {
00372                         CPU_data = v;
00373 
00374                         /* Reset BRDY bit in status register, which means we are full of data */
00375                         if (status_reset_handler && status_change_BRDY_bit)
00376                                 (status_reset_handler)(status_change_which_chip, status_change_BRDY_bit);
00377                         return;
00378                 }
00379 
00380                 break;
00381 
00382         case 0x09:  /* DELTA-N L (ADPCM Playback Prescaler) */
00383         case 0x0a:  /* DELTA-N H */
00384                 delta  = (reg[0xa] * 0x0100 | reg[0x9]);
00385                 step     = uint32_t(double(delta /* *(1<<(YM_DELTAT_SHIFT-16)) */) * freqbase);
00386                 /*logerror("DELTAT deltan:09=%2x 0a=%2x\n",reg[0x9], reg[0xa]);*/
00387                 break;
00388 
00389         case 0x0b:  /* Output level control (volume, linear) */
00390                 {
00391                         const int32_t oldvol = volume;
00392                         volume = (v & 0xff) * (output_range / 256) / YM_DELTAT_DECODE_RANGE;
00393 /*                              v     *     ((1<<16)>>8)        >>  15;
00394 *                       thus:   v     *     (1<<8)              >>  15;
00395 *                       thus: output_range must be (1 << (15+8)) at least
00396 *                               v     *     ((1<<23)>>8)        >>  15;
00397 *                               v     *     (1<<15)             >>  15;
00398 */
00399                         /*logerror("DELTAT vol = %2x\n",v&0xff);*/
00400                         if (oldvol != 0)
00401                         {
00402                                 adpcml = int(double(adpcml) / double(oldvol) * double(volume));
00403                         }
00404                 }
00405                 break;
00406 
00407         case 0x0c:  /* Limit Address L */
00408         case 0x0d:  /* Limit Address H */
00409                 limit  = (reg[0xd] * 0x0100 | reg[0xc]) << (portshift - DRAMportshift);
00410                 /*logerror("DELTAT limit: 0c=%2x 0d=%2x addr=%8x\n",reg[0xc], reg[0xd],limit );*/
00411                 break;
00412         }
00413 }
00414 
00415 void YM_DELTAT::ADPCM_Reset(int panidx, int mode, device_t *dev)
00416 {
00417         device    = dev;
00418         now_addr  = 0;
00419         now_step  = 0;
00420         step      = 0;
00421         start     = 0;
00422         end       = 0;
00423         limit     = ~0; /* this way YM2610 and Y8950 (both of which don't have limit address reg) will still work */
00424         volume    = 0;
00425         pan       = &output_pointer[panidx];
00426         acc       = 0;
00427         prev_acc  = 0;
00428         adpcmd    = 127;
00429         adpcml    = 0;
00430         emulation_mode = uint8_t(mode);
00431         portstate = (emulation_mode == EMULATION_MODE_YM2610) ? 0x20 : 0;
00432         control2  = (emulation_mode == EMULATION_MODE_YM2610) ? 0x01 : 0; /* default setting depends on the emulation mode. MSX demo called "facdemo_4" doesn't setup control2 register at all and still works */
00433         DRAMportshift = dram_rightshift[control2 & 3];
00434 
00435         /* The flag mask register disables the BRDY after the reset, however
00436         ** as soon as the mask is enabled the flag needs to be set. */
00437 
00438         /* set BRDY bit in status register */
00439         if (status_set_handler && status_change_BRDY_bit)
00440                 (status_set_handler)(status_change_which_chip, status_change_BRDY_bit);
00441 }
00442 
00443 void YM_DELTAT::postload(uint8_t *regs)
00444 {
00445         /* to keep adpcml */
00446         volume = 0;
00447         /* update */
00448         for (int r = 1; r < 16; r++)
00449                 ADPCM_Write(r, regs[r]);
00450         reg[0] = regs[0];
00451 
00452         /* current rom data */
00453         if (memory)
00454                 now_data = *(memory + (now_addr >> 1));
00455 
00456 }
00457 void YM_DELTAT::savestate(device_t *device)
00458 {
00459 #ifdef MAME_EMU_SAVE_H
00460         YM_DELTAT *const DELTAT = this; // makes the save name sensible
00461         device->save_item(NAME(DELTAT->portstate));
00462         device->save_item(NAME(DELTAT->now_addr));
00463         device->save_item(NAME(DELTAT->now_step));
00464         device->save_item(NAME(DELTAT->acc));
00465         device->save_item(NAME(DELTAT->prev_acc));
00466         device->save_item(NAME(DELTAT->adpcmd));
00467         device->save_item(NAME(DELTAT->adpcml));
00468 #else
00469     (void)device;
00470 #endif
00471 }
00472 
00473 
00474 #define YM_DELTAT_Limit(val,max,min)    \
00475 {                                       \
00476         if ( val > max ) val = max;         \
00477         else if ( val < min ) val = min;    \
00478 }
00479 
00480 static inline void YM_DELTAT_synthesis_from_external_memory(YM_DELTAT *DELTAT)
00481 {
00482         uint32_t step;
00483         int data;
00484 
00485         DELTAT->now_step += DELTAT->step;
00486         if ( DELTAT->now_step >= (1<<YM_DELTAT_SHIFT) )
00487         {
00488                 step = DELTAT->now_step >> YM_DELTAT_SHIFT;
00489                 DELTAT->now_step &= (1<<YM_DELTAT_SHIFT)-1;
00490                 do{
00491                         if ( DELTAT->now_addr == (DELTAT->limit<<1) )
00492                                 DELTAT->now_addr = 0;
00493 
00494                         if ( DELTAT->now_addr == (DELTAT->end<<1) ) {   /* 12-06-2001 JB: corrected comparison. Was > instead of == */
00495                                 if( DELTAT->portstate&0x10 ){
00496                                         /* repeat start */
00497                                         DELTAT->now_addr = DELTAT->start<<1;
00498                                         DELTAT->acc      = 0;
00499                                         DELTAT->adpcmd   = YM_DELTAT_DELTA_DEF;
00500                                         DELTAT->prev_acc = 0;
00501                                 }else{
00502                                         /* set EOS bit in status register */
00503                                         if(DELTAT->status_set_handler)
00504                                                 if(DELTAT->status_change_EOS_bit)
00505                                                         (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit);
00506 
00507                                         /* clear PCM BUSY bit (reflected in status register) */
00508                                         DELTAT->PCM_BSY = 0;
00509 
00510                                         DELTAT->portstate = 0;
00511                                         DELTAT->adpcml = 0;
00512                                         DELTAT->prev_acc = 0;
00513                                         return;
00514                                 }
00515                         }
00516 
00517                         if( DELTAT->now_addr&1 ) data = DELTAT->now_data & 0x0f;
00518                         else
00519                         {
00520                                 DELTAT->now_data = *(DELTAT->memory + (DELTAT->now_addr>>1));
00521                                 data = DELTAT->now_data >> 4;
00522                         }
00523 
00524                         DELTAT->now_addr++;
00525                         /* 12-06-2001 JB: */
00526                         /* YM2610 address register is 24 bits wide.*/
00527                         /* The "+1" is there because we use 1 bit more for nibble calculations.*/
00528                         /* WARNING: */
00529                         /* Side effect: we should take the size of the mapped ROM into account */
00530                         DELTAT->now_addr &= ( (1<<(24+1))-1);
00531 
00532                         /* store accumulator value */
00533                         DELTAT->prev_acc = DELTAT->acc;
00534 
00535                         /* Forecast to next Forecast */
00536                         DELTAT->acc += (ym_deltat_decode_tableB1[data] * DELTAT->adpcmd / 8);
00537                         YM_DELTAT_Limit(DELTAT->acc,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN);
00538 
00539                         /* delta to next delta */
00540                         DELTAT->adpcmd = (DELTAT->adpcmd * ym_deltat_decode_tableB2[data] ) / 64;
00541                         YM_DELTAT_Limit(DELTAT->adpcmd,YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN );
00542 
00543                         /* ElSemi: Fix interpolator. */
00544                         /*DELTAT->prev_acc = prev_acc + ((DELTAT->acc - prev_acc) / 2 );*/
00545 
00546                 }while(--step);
00547 
00548         }
00549 
00550         /* ElSemi: Fix interpolator. */
00551         DELTAT->adpcml = DELTAT->prev_acc * (int)((1<<YM_DELTAT_SHIFT)-DELTAT->now_step);
00552         DELTAT->adpcml += (DELTAT->acc * (int)DELTAT->now_step);
00553         DELTAT->adpcml = (DELTAT->adpcml>>YM_DELTAT_SHIFT) * (int)DELTAT->volume;
00554 
00555         /* output for work of output channels (outd[OPNxxxx])*/
00556         *(DELTAT->pan) += DELTAT->adpcml;
00557 }
00558 
00559 
00560 
00561 static inline void YM_DELTAT_synthesis_from_CPU_memory(YM_DELTAT *DELTAT)
00562 {
00563         uint32_t step;
00564         int data;
00565 
00566         DELTAT->now_step += DELTAT->step;
00567         if ( DELTAT->now_step >= (1<<YM_DELTAT_SHIFT) )
00568         {
00569                 step = DELTAT->now_step >> YM_DELTAT_SHIFT;
00570                 DELTAT->now_step &= (1<<YM_DELTAT_SHIFT)-1;
00571                 do{
00572                         if( DELTAT->now_addr&1 )
00573                         {
00574                                 data = DELTAT->now_data & 0x0f;
00575 
00576                                 DELTAT->now_data = DELTAT->CPU_data;
00577 
00578                                 /* after we used CPU_data, we set BRDY bit in status register,
00579                                 * which means we are ready to accept another byte of data */
00580                                 if(DELTAT->status_set_handler)
00581                                         if(DELTAT->status_change_BRDY_bit)
00582                                                 (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
00583                         }
00584                         else
00585                         {
00586                                 data = DELTAT->now_data >> 4;
00587                         }
00588 
00589                         DELTAT->now_addr++;
00590 
00591                         /* store accumulator value */
00592                         DELTAT->prev_acc = DELTAT->acc;
00593 
00594                         /* Forecast to next Forecast */
00595                         DELTAT->acc += (ym_deltat_decode_tableB1[data] * DELTAT->adpcmd / 8);
00596                         YM_DELTAT_Limit(DELTAT->acc,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN);
00597 
00598                         /* delta to next delta */
00599                         DELTAT->adpcmd = (DELTAT->adpcmd * ym_deltat_decode_tableB2[data] ) / 64;
00600                         YM_DELTAT_Limit(DELTAT->adpcmd,YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN );
00601 
00602 
00603                 }while(--step);
00604 
00605         }
00606 
00607         /* ElSemi: Fix interpolator. */
00608         DELTAT->adpcml = DELTAT->prev_acc * (int)((1<<YM_DELTAT_SHIFT)-DELTAT->now_step);
00609         DELTAT->adpcml += (DELTAT->acc * (int)DELTAT->now_step);
00610         DELTAT->adpcml = (DELTAT->adpcml>>YM_DELTAT_SHIFT) * (int)DELTAT->volume;
00611 
00612         /* output for work of output channels (outd[OPNxxxx])*/
00613         *(DELTAT->pan) += DELTAT->adpcml;
00614 }
00615 
00616 
00617 
00618 /* ADPCM B (Delta-T control type) */
00619 void YM_DELTAT::ADPCM_CALC()
00620 {
00621 /*
00622 some examples:
00623 value:   START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET   meaning:
00624   80     1      0    0       0       0      0 0 0       Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register
00625   a0     1      0    1       0       0      0 0 0       Synthesis (playing) from EXT.MEMORY to AUDIO,        sample rate in DELTA-N register
00626   C8     1      1    0       0       1      0 0 0       Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register
00627   E8     1      1    1       0       1      0 0 0       Analysis (recording) from AUDIO to EXT.MEMORY,       sample rate in PRESCALER register
00628 
00629   60     0      1    1       0       0      0 0 0       External memory write via ADPCM data register $08
00630   20     0      0    1       0       0      0 0 0       External memory read via ADPCM data register $08
00631 
00632 */
00633 
00634         if ( (portstate & 0xe0)==0xa0 )
00635         {
00636                 YM_DELTAT_synthesis_from_external_memory(this);
00637                 return;
00638         }
00639 
00640         if ( (portstate & 0xe0)==0x80 )
00641         {
00642                 /* ADPCM synthesis from CPU-managed memory (from reg $08) */
00643                 YM_DELTAT_synthesis_from_CPU_memory(this);    /* change output based on data in ADPCM data reg ($08) */
00644                 return;
00645         }
00646 
00647 //todo: ADPCM analysis
00648 //  if ( (portstate & 0xe0)==0xc0 )
00649 //  if ( (portstate & 0xe0)==0xe0 )
00650 
00651         return;
00652 }