home *** CD-ROM | disk | FTP | other *** search
- // Copyright 1993, Mark T. Pflaging
- // Implementation for class SB_SoundFile.
- // Reads a .WAV file (instead a "raw" file).
- // Also maps in sections of EMM for use when playing a sound,
- // and handles "named" sounds with a simple look-up table.
- //
- // Got the format of a .WAV file from:
- // "PRO-16 MULTIMEDIA SYSTEM'S
- // MOST COMMONLY-ASKED
- // QUESTIONS AND ANSWERS
- // July 13, 1992"
- // provided by Media Vision of Fremont, CA.
- //
- // Portions were borrowed from Jeff Bird's (cejjb@marlin.jcu.edu.au)
- // Sound Blaster Freedom routines dated 12 Feb 92
- //
- // -MTP 6/10/93
- #include "sb.hpp"
- #include "sndfile.hpp"
-
- //#include <stdio.h>
- #include <fstream.h>
- #include <io.h>
- #include <string.h>
-
- strSnd SB_SoundFile::sndRefs[MAXSOUNDS];
- int SB_SoundFile::currentSnds = 0;
-
- log_to_phys_map SB_SoundFile::quadphys[4];
-
- SB_SoundFile * SB_SoundFile::Find(char * ref)
- {
- for (int i = 0; i < currentSnds; i ++) {
- if (!strcmp(ref, sndRefs[i].name)) {
- return sndRefs[i].sound;
- }
- }
- return NULL;
- }
-
- void SB_SoundFile::KillAllSounds()
- {
- for (int i = 0; i < currentSnds; i ++) {
- delete sndRefs[i].name;
- delete sndRefs[i].sound;
- }
- }
-
- SB_SoundFile * SB_SoundFile::current_file = NULL;
- extern int DMA_complete;
-
- int SB_SoundFile::current_page;
- int SB_SoundFile::pages_left;
- int SB_SoundFile::is_not_maptime;
- unsigned long SB_SoundFile::bytes_left;
- SoundBlaster * SB_SoundFile::device;
-
- // Interrupt handler for DMA complete IRQ from Soundblaster
- void far interrupt SBHandler(...)
- {
- disable();
-
- // Acknowledge the interrupt
- inportb(DSP_DATA_AVAIL);
- outportb(0x20,0x20);
- if (SB_SoundFile::nextDMAtransfer()) {
- DMA_complete = 1;
- }
- enable();
- }
-
- int min(int v1, int v2)
- {
- return ((v1 < v2) ? v1 : v2);
- }
-
- Boolean SB_SoundFile::NextDMASegment()
- {
- if (!pages_left) return True; // Done!!
- int temp;
- if (pages_left > 1) {
- sl = 16383;
- bytes_left -= long(sl);
- temp = 1;
- }
- else {
- temp = pages_left;
- sl = (unsigned int)bytes_left; // Should be < 16383!
- }
-
- if (!is_not_maptime)
- MapInSound(current_page, min(4, pages_left));
- pages_left -= temp;
- current_page += temp;
-
- unsigned IOaddr = device->getIOaddr();
- // Setup device
- device->Reset();
- device->Sample_Rate(sr);
- device->Voice(True);
-
- sl --;
- // Setup DMA
- dma_reset(device->getDMAchan());
- dma_setup(device->getDMAchan(), getPageFrame() + (is_not_maptime * 16384), sl, 1);
- is_not_maptime ++;
- is_not_maptime %= 4;
-
- // Turn on stereo output
- if(stereo && (device->getType() == SBPro)) writemixer(0x0e,0x13);
-
- // Setup Soundblaster for transfer
- // Would be nice to allow 16 bit files!
- writedac(DMA_8_BIT_DAC);
-
- // Write length
- writedac(sl & 0xff);
- writedac(sl >> 8);
-
- return False; // Continue...
- }
-
- /********************************WAV FILE FORMAT***********************************
- 4 bytes 'RIFF'
- 4 bytes <length>
- 4 bytes 'WAVE'
- 4 bytes 'fmt '
- 4 bytes <length> ; 10h - length of 'data' block
- 2 bytes 01 ; format tag
- 2 bytes 01 ; channels (1=mono, 2=stereo)
- 4 bytes xxxx ; samples per second
- 4 bytes xxxx ; average samples per second
- 2 bytes 01 ; block alignment
- 2 bytes 08 ; bits per sample
- 4 bytes 'data'
- 4 bytes <length>
- bytes <sample data>
- **********************************************************************************/
-
- Boolean SB_SoundFile::ReadHeader(int fd)
- {
- struct wav_header header;
- if (_read(fd, &header, sizeof(struct wav_header)) != sizeof(struct wav_header))
- return False;
- if (strncmp(header.id1, "RIFF", 4)) return False;
-
- if (strncmp(header.id2, "WAVEfmt ", 8)) return False;
- if (header.blklen != 0x10) return False;
- if (header.indicator != 1) return False;
- switch(header.stereoval) {
- case 1:
- setStereo(False);
- break;
- case 2:
- setStereo(True);
- break;
- default:
- return False;
- }
- sr = header.sr;
-
- // I'm not really sure what to do with these numbers at
- // present. They really just seem to be a restatement of
- // the sample rate, but maybe I'm missing something...
- if ((header.blkpersec / header.blkspersamp) != sr) return False;
-
- // Sound Blaster can only handle 8 bit samples....
- if (header.bits_per_sample != 8) return False;
-
- if (strncmp(header.id3, "data", 4)) return False;
- sample_len = header.sample_len;
- // Whew! Success.
- return True;
- }
-
- #include <fcntl.h>
- #include <sys\stat.h>
- void SB_SoundFile::Init(char * refname, char * filenm)
- {
- InitRef(refname);
-
- int fd = open(filenm, O_RDONLY | O_BINARY);
- if (fd == -1) {
- cerr << "Could not open sample file " << filenm << endl;
- exit(1);
- }
-
-
- if (!ReadHeader(fd)) {
- close(fd);
- cerr << "Some sort of problem with sample file " << filenm << endl;
- return;
- }
-
-
- #ifdef OLD_WAY
- if (sample_len > 64000)
- sl = 64000;
- else
- sl = (unsigned)sample_len;
- raw = (signed char far *)farmalloc((unsigned long)sl + 65535L);
- unsigned long physical = ((unsigned long)FP_OFF(raw)) + (((unsigned long)FP_SEG(raw)) << 4);
- unsigned long aligned_physical = physical+0x0FFFFL;
- aligned_physical &= 0xF0000L;
- aligned=(char *)MK_FP((unsigned )((aligned_physical >> 4) & 0xFFFF),0);
- _read(fd, aligned, sl);
- #else
- unsigned long left = sample_len;
- pages = 0;
- Boolean done = False;
- first_page = CurrentlyAllocated(); // zero-relative
- int temp;
- last_page = first_page;
-
- while (!done) {
- if (left > 16383) {
- sl = 16363;
- left -= 16383L;
- temp = 1;
- }
- else {
- sl = (unsigned int) left;
- temp = 1;
- done = True;
- }
- pages += temp;
- Allocate(temp);
- MapInSound(last_page, temp);
- _read(fd, getPageFrame(), sl);
- last_page += temp;
- }
- #endif
- close(fd);
- }
-
- #ifndef OLD_WAY
- void SB_SoundFile::MapInSound(int first, int howmany)
- {
- for (int i = 0; i < howmany; i ++) {
- quadphys[i].log_page_number = i + first;
- quadphys[i].phys_page_number = i;
- }
- MapMultiple(quadphys, howmany);
- }
- #endif
-
- void SB_SoundFile::OutVoice_DMA(SoundBlaster & device_arg)
- {
- device = &device_arg;
- bytes_left = sample_len;
- current_page = first_page;
- pages_left = pages;
- is_not_maptime = 0;
- current_file = this;
-
- unsigned char im, tm;
- device_arg.reset_DMA_Complete();
-
- // Enable interrupts on PIC
- disable();
- im = inportb(0x21);
- tm = ~(1 << device_arg.getIRQ());
- outportb(0x21,im & tm);
- enable();
-
- NextDMASegment();
- }
-
-