⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tl_sb.c

📁 gameboy 模拟器的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
   sb.dma = detect_dma(false);   if ((uint8) INVALID == sb.dma)      return -1;   /* may or may not exist */   sb.dma16 = detect_dma(true);   return 0;}/*** Probe for an SB*/static int sb_probe(void){   int retval;   retval = parse_blaster_env();   /* if environment parse failed, try brute force autodetection */   if (-1 == retval)      retval = sb_detect();   /* no blaster found */   if (-1 == retval)   {      thin_printf("thinlib.sb: no sound blaster found\n");      return -1;   }   if (dsp_reset())   {      thin_printf("thinlib.sb: could not reset SB DSP: check BLASTER= variable\n");      return -1;   }   sb.dsp_version = dsp_getversion();   return 0;}/*** Interrupt handler for 8/16-bit audio */static int sb_isr(void){   uint32 address, offset;   dma.count++;   /* NOTE: this only works with 8-bit, as one-shot mode   ** does not seem to work with 16-bit transfers   */   if (false == dma.autoinit)   {      dsp_write(DSP_DMA_DAC_8BIT);      dsp_write(LOW_BYTE(sb.buf_size - 1));      dsp_write(HIGH_BYTE(sb.buf_size - 1));   }   /* indicate we got the interrupt */   inportb(dma.ackport);   /* determine the current playback position */   address = inportb(dma.addrport);   address |= (inportb(dma.addrport) << 8);   address -= dos.offset;   if (address < sb.buf_size)      offset = sb.buf_chunk;   else      offset = 0;   sb.callback(sb.user_data, sb.buffer + offset, sb.buf_size);   /* if we haven't enabled near pointers, we've written to a double   ** buffer, so transfer it to low DOS memory area   */   if (0 == thinlib_nearptr)      dosmemput(sb.buffer + offset, sb.buf_chunk, dos.bufaddr + offset);   /* acknowledge interrupt was taken */   if (sb.irq > 7)      outportb(0xA0, 0x20);   outportb(0x20, 0x20);   return 0;}THIN_LOCKED_STATIC_FUNC(sb_isr)/* install the SB ISR */static void sb_setisr(void){   THIN_DISABLE_INTS();   thin_int_install(SB_IRQVEC(sb.irq), sb_isr);   /* enable IRQ */   thin_irq_enable(sb.irq);   THIN_ENABLE_INTS();}static void sb_restoreisr(void){   THIN_DISABLE_INTS();   /* restore IRQ to previous state */   thin_irq_restore(sb.irq);   thin_int_remove(SB_IRQVEC(sb.irq));   THIN_ENABLE_INTS();}/* allocate sound buffers */static int sb_allocate_buffers(int buf_size){   int double_bufsize;   sb.buf_size = buf_size;//   if (sb.format & SB_FORMAT_STEREO)//      sb.buf_size *= 2;   if (sb.format & SB_FORMAT_16BIT)      sb.buf_chunk = sb.buf_size * sizeof(uint16);   else      sb.buf_chunk = sb.buf_size * sizeof(uint8);   double_bufsize = 2 * sb.buf_chunk;   dos.buffer.size = (double_bufsize + 15) >> 4;   if (_go32_dpmi_allocate_dos_memory(&dos.buffer))      return -1;   /* calc linear address */   dos.bufaddr = dos.buffer.rm_segment << 4;   if (sb.format & SB_FORMAT_16BIT)   {      dos.page = (dos.bufaddr >> 16) & 0xFF;      dos.offset = (dos.bufaddr >> 1) & 0xFFFF;   }   else   {      dos.page = (dos.bufaddr >> 16) & 0xFF;      dos.offset = dos.bufaddr & 0xFFFF;   }   if (thinlib_nearptr)   {      sb.buffer = (uint8 *) THIN_PHYSICAL_ADDR(dos.bufaddr);   }   else   {      sb.buffer = malloc(double_bufsize);      if (NULL == sb.buffer)         return -1;   }   /* clear out the buffers */   if (sb.format & SB_FORMAT_SIGNED)      memset(sb.buffer, SILENCE_SIGNED, double_bufsize);   else      memset(sb.buffer, SILENCE_UNSIGNED, double_bufsize);   if (0 == thinlib_nearptr)      dosmemput(sb.buffer, double_bufsize, dos.bufaddr);   return 0;}/* free buffers */static void sb_free_buffers(void){   sb.callback = NULL;   _go32_dpmi_free_dos_memory(&dos.buffer);   if (0 == thinlib_nearptr)   {      free(sb.buffer);      sb.buffer = NULL;   }   sb.buffer = NULL;}/* get rid of all things SB */void thin_sb_shutdown(void){   if (true == sb.initialized)   {      sb.initialized = false;      dsp_reset();      sb_restoreisr();            sb_free_buffers();   }}/* initialize sound bastard */int thin_sb_init(int *sample_rate, int *buf_size, int *format){#define  CLAMP_RATE(in_rate, min_rate, max_rate) \                    (in_rate < min_rate ? min_rate : \                    (in_rate > max_rate ? max_rate : in_rate))      /* don't init twice! */   if (true == sb.initialized)      return 0;   /* lock variables, routines */   THIN_LOCK_VAR(dma);   THIN_LOCK_VAR(dos);   THIN_LOCK_VAR(sb);   THIN_LOCK_FUNC(sb_isr);   memset(&sb, 0, sizeof(sb));      if (sb_probe())      return -1;   /* try autoinit DMA first */   dma.autoinit = true;   sb.format = (uint8) *format;   /* determine which SB model we have, and act accordingly */   if (sb.dsp_version < DSP_VERSION_SB_15)   {      /* SB 1.0 */      sb.sample_rate = CLAMP_RATE(*sample_rate, 4000, 22050);      sb.format &= ~(SB_FORMAT_16BIT | SB_FORMAT_STEREO);      dma.autoinit = false;   }   else if (sb.dsp_version < DSP_VERSION_SB_20)   {      /* SB 1.5 */      sb.sample_rate = CLAMP_RATE(*sample_rate, 5000, 22050);      sb.format &= ~(SB_FORMAT_16BIT | SB_FORMAT_STEREO);   }   else if (sb.dsp_version < DSP_VERSION_SB_PRO)   {      /* SB 2.0 */      sb.sample_rate = CLAMP_RATE(*sample_rate, 5000, 44100);      sb.format &= ~(SB_FORMAT_16BIT | SB_FORMAT_STEREO);   }   else if (sb.dsp_version < DSP_VERSION_SB16)   {      /* SB Pro */      if (sb.format & SB_FORMAT_STEREO)         sb.sample_rate = CLAMP_RATE(*sample_rate, 5000, 22050);      else         sb.sample_rate = CLAMP_RATE(*sample_rate, 5000, 44100);      sb.format &= ~SB_FORMAT_16BIT;   }   else   {      /* SB 16 */      sb.sample_rate = CLAMP_RATE(*sample_rate, 5000, 44100);   }   /* sanity check for 16-bit */   if ((sb.format & SB_FORMAT_16BIT) && ((uint8) INVALID == sb.dma16))   {      sb.format &= ~SB_FORMAT_16BIT;      thin_printf("thinlib.sb: 16-bit DMA channel not available, dropping to 8-bit\n");   }   /* clamp buffer size to something sane */   if ((uint16) *buf_size > sb.sample_rate)   {      *buf_size = sb.sample_rate;      thin_printf("thinlib.sb: buffer size too big, dropping to %d bytes\n", *buf_size);   }   /* allocate buffer / DOS memory */   if (sb_allocate_buffers(*buf_size))   {      thin_printf("thinlib.sb: failed allocating sound buffers\n");      return -1;   }   /* set the new IRQ vector! */   sb_setisr();   sb.initialized = true;   /* return the actual values */   *sample_rate = sb.sample_rate;   *buf_size = sb.buf_size;   *format = sb.format;   return 0;}void thin_sb_stop(void){   if (true == sb.initialized)   {      if (sb.format & SB_FORMAT_16BIT)      {         dsp_write(DSP_DMA_PAUSE_16BIT);  /* pause 16-bit DMA */         dsp_write(DSP_DMA_STOP_8BIT);         dsp_write(DSP_DMA_PAUSE_16BIT);      }      else      {         dsp_write(DSP_DMA_PAUSE_8BIT);  /* pause 8-bit DMA */         dsp_write(DSP_SPEAKER_OFF);      }   }}/* return time constant for older sound bastards */static uint8 get_time_constant(int rate){   return ((65536 - (256000000L / rate)) / 256);}static void init_samplerate(int rate){   if ((sb.format & SB_FORMAT_16BIT) || sb.dsp_version >= DSP_VERSION_SB16)   {      dsp_write(DSP_DMA_DAC_RATE);      dsp_write(HIGH_BYTE(rate));      dsp_write(LOW_BYTE(rate));   }   else   {      dsp_write(DSP_DMA_TIME_CONST);      dsp_write(get_time_constant(rate));   }}/* set the sample rate */void thin_sb_setrate(int rate){   if (sb.format & SB_FORMAT_16BIT)   {      dsp_write(DSP_DMA_PAUSE_16BIT);  /* pause 16-bit DMA */      init_samplerate(rate);      dsp_write(DSP_DMA_CONT_16BIT);   /* continue 16-bit DMA */   }   else   {      dsp_write(DSP_DMA_PAUSE_8BIT);   /* pause 8-bit DMA */      init_samplerate(rate);      dsp_write(DSP_DMA_CONT_8BIT);    /* continue 8-bit DMA */   }   sb.sample_rate = rate;}/* start SB DMA transfer */static void start_transfer(void){   uint8 dma_mode, start_command, mode_command;   int dma_length;   /* reset DMA count */   dma.count = 0;   dma_length = sb.buf_size * 2;   if (true == dma.autoinit)   {      start_command = DSP_DMA_DAC_MODE;   /* autoinit DMA */      dma_mode = DMA_AUTOINIT_MODE;   }   else   {      start_command = 0;      dma_mode = DMA_ONESHOT_MODE;   }   /* things get a little bit nasty here, look out */   if (sb.format & SB_FORMAT_16BIT)   {      uint8 dma_base = sb.dma16 - 4;      dma_mode |= dma_base;       start_command |= DSP_DMA_START_16BIT;      outportb(DMA_MASKPORT_16BIT, DMA_STOPMASK_BASE | dma_base);      outportb(DMA_MODEPORT_16BIT, dma_mode);      outportb(DMA_CLRPTRPORT_16BIT, 0x00);      outportb(DMA_ADDRBASE_16BIT + (4 * dma_base), LOW_BYTE(dos.offset));      outportb(DMA_ADDRBASE_16BIT + (4 * dma_base), HIGH_BYTE(dos.offset));      outportb(DMA_COUNTBASE_16BIT + (4 * dma_base), LOW_BYTE(dma_length - 1));      outportb(DMA_COUNTBASE_16BIT + (4 * dma_base), HIGH_BYTE(dma_length - 1));      outportb(dma16_ports[dma_base], dos.page);      outportb(DMA_MASKPORT_16BIT, DMA_STARTMASK_BASE | dma_base);      dma.ackport = sb.baseio + DSP_DMA_ACK_16BIT;      dma.addrport = DMA_ADDRBASE_16BIT + (4 * (sb.dma16 - 4));   }   else   {      dma_mode |= sb.dma;      start_command |= DSP_DMA_START_8BIT;      outportb(DMA_MASKPORT_8BIT, DMA_STOPMASK_BASE + sb.dma);      outportb(DMA_MODEPORT_8BIT, dma_mode);      outportb(DMA_CLRPTRPORT_8BIT, 0x00);      outportb(DMA_ADDRBASE_8BIT + (2 * sb.dma), LOW_BYTE(dos.offset));      outportb(DMA_ADDRBASE_8BIT + (2 * sb.dma), HIGH_BYTE(dos.offset));      outportb(DMA_COUNTBASE_8BIT + (2 * sb.dma), LOW_BYTE(dma_length - 1));      outportb(DMA_COUNTBASE_8BIT + (2 * sb.dma), HIGH_BYTE(dma_length - 1));      outportb(dma8_ports[sb.dma], dos.page);      outportb(DMA_MASKPORT_8BIT, DMA_STARTMASK_BASE + sb.dma);      dma.ackport = sb.baseio + DSP_DMA_ACK_8BIT;      dma.addrport = DMA_ADDRBASE_8BIT + (2 * sb.dma);   }   /* check signed/unsigned */   if (sb.format & SB_FORMAT_SIGNED)      mode_command = DSP_DMA_SIGNED;   else      mode_command = DSP_DMA_UNSIGNED;   /* check stereo */   if (sb.format & SB_FORMAT_STEREO)      mode_command |= DSP_DMA_STEREO;   else      mode_command |= DSP_DMA_MONO;   init_samplerate(sb.sample_rate);   /* start things going */   if ((sb.format & SB_FORMAT_16BIT) || sb.dsp_version >= DSP_VERSION_SB16)   {      dsp_write(start_command);      dsp_write(mode_command);      dsp_write(LOW_BYTE(sb.buf_size - 1));      dsp_write(HIGH_BYTE(sb.buf_size - 1));   }   else   {      /* turn on speaker */      dsp_write(DSP_SPEAKER_ON);      if (true == dma.autoinit)      {         dsp_write(DSP_DMA_BLOCK_SIZE);  /* set buffer size */         dsp_write(LOW_BYTE(sb.buf_size - 1));         dsp_write(HIGH_BYTE(sb.buf_size - 1));         if (sb.dsp_version < DSP_VERSION_SB_20)            dsp_write(DSP_DMA_DAC_AI_8BIT); /* low speed autoinit */         else            dsp_write(DSP_DMA_DAC_HS_8BIT);      }      else      {         dsp_write(DSP_DMA_DAC_8BIT);         dsp_write(LOW_BYTE(sb.buf_size - 1));         dsp_write(HIGH_BYTE(sb.buf_size - 1));      }   }}/* TODO: this gets totally wacked when we change the timer rate!!! *//* start playing the output buffer */int thin_sb_start(sbmix_t fillbuf, void *user_data){   clock_t count;   int projected_dmacount;   /* make sure we really should be here... */   if (false == sb.initialized || NULL == fillbuf)      return -1;   /* stop any current processing */   thin_sb_stop();   /* set the callback routine */   sb.callback = fillbuf;   sb.user_data = user_data;   /* calculate how many DMAs we should have in one second    ** and scale it down just a tad   */   projected_dmacount = (int) ((0.8 * sb.sample_rate) / sb.buf_size);   if (projected_dmacount < 1)      projected_dmacount = 1;   /* get the transfer going, so we can ensure interrupts are firing */   start_transfer();   count = clock();   while ((clock() - count) < CLOCKS_PER_SEC && dma.count < projected_dmacount)      ; /* spin */   if (dma.count < projected_dmacount)   {      if (true == dma.autoinit)      {         thin_printf("thinlib.sb: Autoinit DMA failed, trying one-shot mode.\n");         dsp_reset();         dma.autoinit = false;         dma.count = 0;         return (thin_sb_start(fillbuf, user_data));      }      else      {         thin_printf("thinlib.sb: One-shot DMA mode failed, sound will not be heard.\n");         thin_printf("thinlib.sb: DSP version: %d.%d baseio: %X IRQ: %d DMA: %d High: %d\n",                     sb.dsp_version >> 8, sb.dsp_version & 0xFF,                     sb.baseio, sb.irq, sb.dma, sb.dma16);         return -1;      }   }   return 0;}/*** $Log: $*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -