First post, by Lassar
- Rank
- Newbie
😳
I was messing around with a PowerBasic Version of DmaPlay.bas
I finally got it to work. Then I decided to get rid of a bunch of subroutines I was not using.
It stopped working in DosBox. It was still working very good under XP. I started to compare the differences between this version to a previous version that worked in DosBox.
I finally narrowed down the diffence that caused it to stopped working
under DosBox.
All I had done was to take out routines I was not using. Nothing else.
Talk about a unusual bug.
If you doubt me here is the code.
'---------------------------------------------------------------------------' DMA Play 6.0 Beta Build 11.10.98: released for beta testing ONLY!' a versatile DMA-based sound (.WAV) file player in QBasic and QB45.' by Mike Huff (v1), Martin Rampersad (v2), Toshi Horie (v3,4,5,6)' Realtime 16-bit to 8-bit stereo/mono conversions added up to 44Khz' Realtime 16-bit and 8-bit mixing possible on Pentium 120Mhz+.' Program downloaded from http://www.ocf.berkeley.edu/~horie/project.html' ------------- programming notes ----------------' Thanks: * Ethan Brodsky, who made DMAPLAY4+ possible.' * Angelo Mottola for his support and testing on SB16.' * Michael Sorensen for his brilliant ideas and feedback.' Features: * 8-bit and 16-bit 2 channel mixing.' * Tested with an SB Pro and SB AWE32.' * simplified calling scheme: PlayWave Filename$' * new 8-bit 'generic DMA' handler for SB16.' * bugfix: Now all files tested finish playing.' Future Plans* complete 8 channel mixer routine' * EMS sound buffer swapping support' * interrupt and autoinit mode support (thanks to Michael)' Legal: * Toshihiro Horie will not be liable for any damages' resulting from the use or misuse of this program.'---------------------------------------------------------------------------OPTION BINARY BASE 1DEFINT A-Z$STATICTYPE WaveInfoTypeStereoWav AS INTEGERFreq AS LONGLength AS LONGplaytime AS DOUBLEsixteenbit AS INTEGEREND TYPETYPE WaveHeaderTypeRiffID AS STRING * 4 'should be 'RIFF'RiffLength AS LONG'rept. chunk id and size then chunk dataWavID AS STRING * 4 'should be 'WAVE'FmtID AS STRING * 4FmtLength AS LONG'FMT ' chunk - common fieldswavformattag AS INTEGER ' word - format category e.g. 0x0001=PCMChannels AS INTEGER ' word - number of Channels 1=mono 2=stereoSamplesPerSec AS LONG 'dword - sampling rate e.g. 44100HzavgBytesPerSec AS LONG 'dword - to estimate buffer sizeblockalign AS INTEGER ' word - buffer size must be int. multiple of thisFmtSpecific AS INTEGER ' wordDataID AS STRING * 4DataLength AS LONGEND TYPEDECLARE SUB PlayWave (Filename$)DECLARE SUB getWaveInfo ()DECLARE FUNCTION DMADone% (DMA16%, L??)DECLARE FUNCTION ResetDSP% ()DECLARE FUNCTION ReadDSP% ()DECLARE FUNCTION ReadDAC% ()DECLARE SUB VocVolume (Right1%, Left1%, Getvol%)DECLARE SUB MasterVolume (Right1%, Left1%, Getvol%)DECLARE SUB WriteDSP (Byte2%)
DECLARE SUB SpeakerState (OnOff%)DECLARE SUB DMAState (StopGo%)DECLARE SUB DMAPlay (Segment??, offset??, Length??, Freq&, StereoWav%)DECLARE SUB GetBLASTER ()DECLARE FUNCTION DSPVersion! ()SHARED Baseport%, LenPort%, DMA%, DMA16%, IRQ%, cardversion%, SoundLen??Playerversion$ = "DMAPlay 6.0b"DIM Wave AS WaveHeaderTypeDIM WaveInfo AS WaveInfoTypeSHARED WaveSHARED WaveInfoSCREEN 0: CLS'WIDTH 80, 50PRINT Playerversion$PRINT "By Mike Huff (SB, SBPro) and Toshi Horie (SB16, SBPro realtime conv/mixing)"PRINT "Modified By Martin Rampersad (To play entire file instead of first 32k)"PRINT "Comments, etc. can be sent to MHuff@gnn.com or to Martin_Rampersad@juno.com"Baseport% = &H220: IRQ% = 5: DMA% = 1: 'defaultGetBLASTER ' Parses BLASTER environmentPRINT STRING$(80, 196)Left1% = 12: Right1% = 12ResetDSP%SpeakerState 1MasterVolume 20, 20, 0VocVolume 20, 20, 0'MasterVolume Right1%, Left1%, 1PRINT "Master volume is set at: Right-"; Right1%; " Left-"; Left1%'WavBuffer size MUST be divisible by 4 for stereo filesSoundLen?? = 65528DIM STATIC WavBuffer&(16382)SHARED WavBuffer&()%HeaderSize = 45 'assume .WAV file (use 45 because 1st bytePlayWave COMMAND$DMAState 0: 'stop soundQuit% = ResetDSP%CLOSEENDFUNCTION DMADone% (DMA16%, L??)countlo% = INP( LenPort%)counthi% = INP(LenPort%)IF counthi% = 255 AND countlo% = 255 THENIF DMA16% THENack16% = INP(Baseport% + &HF) 'ack to SB'OUT &HA0, &H20 'acknowledge SB interrupt 8-15'OUT &H20, &H20 'acknowledge SB interrupt 1-15ELSEack% = INP(Baseport% + &HE)'OUT &H20, &H20 'acknowledge SB interrupt 1-15END IFDMADone% = -1'SOUND 300, .4END IFEND FUNCTION$SEGMENTSUB DMAPlay (Segment??, offset??, Length??, Freq&, StereoWav%)Length?? = Length?? - 1page% = 0Addr& = Segment?? * 16 + OffSet??SELECT CASE DMA%CASE 0PgPort% = &H87AddPort% = &H0LenPort% = &H1ModeReg% = &H48CASE 1PgPort% = &H83AddPort% = &H2LenPort% = &H3ModeReg% = &H49CASE 2PgPort% = &H81AddPort% = &H4LenPort% = &H5ModeReg% = &H4ACASE 3PgPort% = &H82AddPort% = &H6LenPort% = &H7ModeReg% = &H4BCASE ELSEPRINT "8-bit DMA channels 0-3 only!": ENDEXIT SUBEND SELECTLengthlo% = Length?? AND &HFFLengthhi% = (Length?? AND &HFF00&) \ &H100OUT &HA, &H4 + DMA%: 'DMA channel to use (DRQ#)OUT &HC, &H0OUT &HB, ModeReg%OUT AddPort%, Addr& AND &HFF: 'buffer address of sound data low byteOUT AddPort%, (Addr& AND &HFF00&) \ &H100: 'high byteIF (Addr& AND 65536) THEN page% = page% + 1: '64K pages for 8-bit DMAIF (Addr& AND 131072) THEN page% = page% + 2IF (Addr& AND 262144) THEN page% = page% + 4IF (Addr& AND 524288) THEN page% = page% + 8OUT PgPort%, page%: 'output page of phys. addr of sample blockOUT LenPort%, Lengthlo%: 'size of block to DMA controller -LowOUT LenPort%, Lengthhi%: 'high byteOUT &HA, DMA%: 'release DMA channelLOCATE 21, 1: PRINT "seg:"; DEC2HEX$(Segment??),PRINT "offset:"; DEC2HEX$(OffSet??), "addr:"; DEC2HEX$(addr&)TimeConst% = 256 - 1000000 \ Freq&IF Freq& < 22728 THENWriteDSP &H40WriteDSP TimeConst%WriteDSP &H14: '8 bit output over DMAWriteDSP (Length?? AND &HFF)WriteDSP ((Length?? AND &HFFFF&) \ &H100)ELSE 'SBPro (DSP version 3.x) can play 8-bit mono/stereo wave filesIF cardversion% > 2 THEN'high speed 8 bit output up to 44kHz mono or 22Khz stereoWriteDSP &H40: 'output sampling rate constWriteDSP TimeConst%WriteDSP &H48WriteDSP Lengthlo%WriteDSP Lengthhi%WriteDSP &H91ELSEPRINT "Current Freq&="; Freq&PRINT "You need a Sound Blaster Pro to play at 8 bit high speed.": ENDEND IFEND IFEND SUBSUB DMAState (StopGo%)' Stops or continues DMA play.IF StopGo% THEN WriteDSP &HD4 ELSE WriteDSP &HD0END SUBFUNCTION DSPVersion!' Gets the DSP version.WriteDSP &HE1Temp% = ReadDSP%temp2% = ReadDSP%Temp$ = TRIM$(STR$(Temp%))Temp2$ = TRIM$(STR$(Temp2%))IF temp2% < 10 THENDSPVersion! = VAL(Temp$ + ".0" + Temp2$)ELSEDSPVersion! = VAL(Temp$ + "." + Temp2$)END IF'MODEL VERSION'SB 1.0 1.?? (1.05???, err=2.00)'SB 1.5 1.?? (1.05???)'SB 2.0 2.xx (2.01)'SB Pro 3.00 (???)'SB Pro 2 3.01+ (3.01, 3.02)'SB 16 4.0x (4.04, 4.05)'SB 16 SCSI-2 4.11 (4.11)'SB AWE 32 4.12+ (4.12)END FUNCTIONSUB GetBLASTER' This subroutine parses the BLASTER environment string' and returns the sound card settings' implicitly using COMMON variables Baseport%, DMA%, DMA16%blaster$ = ENVIRON$("BLASTER")IF LEN(blaster$) = 0 THENPRINT "BLASTER environment variable not set."INPUT "Would you like to try the defaults? <y/n>"; ck$IF ck$ = "Y" OR ck$ = "y" THENblaster$ = "A220 I5 D1 H5"ELSEPRINT "Goodbye."ENDEND IFELSEFOR index% = 1 TO LEN(blaster$)SELECT CASE MID$(UCASE$(blaster$), index%, 1)CASE "A"Baseport% = VAL("&H" + MID$(blaster$, index% + 1, 3))CASE "I"IRQ% = VAL(MID$(blaster$, index% + 1, 1))CASE "D"DMA% = VAL(MID$(blaster$, index% + 1, 1))CASE "H"DMA16% = VAL(MID$(blaster$, index% + 1, 1))END SELECTNEXTEND IFIF ResetDSP% = 0 THEN 'resets DSP (returns true if sucessful)PRINT "Sound card NOT found at " + HEX$(Baseport%) + "H."PRINT "Either your card is not SB-compatible or it is set up wrong."ENDEND IFPRINT "Sound Card DSP version:"; DSPVersion!cardversion% = INT(DSPVersion!)END SUBSUB getWaveInfoWaveInfo.Freq = Wave.SamplesPerSecPRINT "SamplesPerSec:"; WaveInfo.Freq&'assume no weird sampling rate like 9bit/sec'PRINT "should equal blockalign:"; (Wave.avgBytesPerSec / Freq&)PRINT "BlockAlign:"; Wave.blockalignIF (SoundLen?? MOD Wave.blockalign) <> 0 THEN PRINT "Internal error: make SoundLen??=32752": ENDPRINT "FmtSpecific:"; Wave.FmtSpecific; "bits/sample"IF Wave.FmtSpecific = 16 THEN WaveInfo.sixteenbit = 1'PRINT "DataID:"; Wave(0).DataIDIF UCASE$(Wave.DataID) <> "DATA" THEN PRINT "Not Data chunk": ENDPRINT "DataLength:"; Wave.DataLength; "bytes"WaveInfo.Length = Wave.DataLengthWaveInfo.playtime# = WaveInfo.Length / WaveInfo.Freq& / Wave.blockalignpmin = INT(WaveInfo.playtime#) \ 60psec = INT(WaveInfo.playtime#) MOD 60IF pmin > 0 THENPRINT USING "Play Length: ##:"; pmin;PRINT USING "##"; psecELSEPRINT USING "Play Length ##.##s"; WaveInfo.playtime#END IF'PRINT "start of actual data:"; SEEK(1)END SUBSUB MasterVolume (Right1%, Left1%, Getvol%)OUT Baseport% + 4, &H22IF Getvol% THENLeft1% = INP(Baseport% + 5) \ 16Right1% = INP(Baseport% + 5) AND &HFEXIT SUBELSEOUT Baseport% + 5, (Right1% + Left1% * 16) AND &HFFEND IFEND SUB$SEGMENTSUB PlayWave (Filename$)FileNum% = FREEFILELOCATE 7, 1OPEN Filename$ FOR BINARY AS FileNum%IF LOF(FileNum%) = 0 THENPRINT "**"; Filename$; " doesn't exist.**"CLOSE : KILL Filename$: ENDEND IFSoundLen& = LOF(FileNum%)-44IF SoundLen& < 65528 THENSoundLen?? = SoundLen&END IFL?? = SoundLen??PRINT : PRINT "Playing " + Filename$GET #FileNum%, , Wave: 'BASIC defines beginning of file as 1Freq& = 22000: 'default playback frequencygetWaveInfoFreq& = WaveInfo.FreqFreq2& = Freq& * 2StereoWav% = WaveInfo.StereoWavsixteenbit% = WaveInfo.sixteenbitcskip = cardversion% <= 3 AND NOT sixteenbit% AND StereoWav%: 'skip one'cskip2 = cardversion% <= 2 AND NOT sixteenbit% AND NOT StereoWav%LOCATE 1, 65: PRINT "cycles free"MEMPACKBseg?? = VARSEG(WavBuffer&(0))Boff?? = VARPTR(WavBuffer&(0))CLSPRINT "Bseg?? = ";Bseg??PRINT "Boff? = ";Boff??vol = 10'LOCATE 18, 1: PRINT "Buffer at " + HEX$(Bseg??); ":"; HEX$(Boff??)RLength& = WaveInfo.Length: 'RLength& is number of remaining bytesIF RLength& > (LOF(FileNum%) - %HeaderSize + 1) THENRLength& = LOF(FileNum%) - %HeaderSize + 1LOCATE 20, 1: PRINT "warning: Truncated .WAV detected."END IFfirsttime = 1GetArray FileNum%, WavBuffer&(), L??, BytesRead??IF RLength& >= SoundLen?? THENL?? = SoundLen??L?? = SoundLen??ELSEL?? = RLength&L?? = CINT(RLength&)END IFt1# = TIMERDOIF RLength& <= 0 AND firsttime = 0 THEN EXIT SUBfirsttime = 0'............play block in the background.......................LOCATE P% + 20,5PRINT "Playing"INCR P%LOCATE 1, 13: COLOR 14DMAPlay Bseg??, BOff??, L??, Freq&, StereoWav%'..............................................................'fill bufferIF RLength& >= SoundLen?? THENL?? = SoundLen??L?? = SoundLen??ELSEL?? = RLength&L?? = SoundLen??END IFGetArray FileNum%,WavBuffer&(),L??,ReadBytes??RLength& = RLength& - L?? 'update remaining length'done filling buffer,,,,,,,,,,,,,,last:cycles% = 0DO UNTIL DMADone%(DMA16%, L??)IF INKEY$ > "" THEN stopflag = 1:EXIT LOOPLOOPIF stopflag THEN EXIT DO: 'stop here so it doesn't freeze the computerLOOPLOCATE 23, 1: PRINT "DMA transfer completed!";DMAState 0: 'stop soundquit% = ResetDSP%END SUBFUNCTION ReadDAC%' Reads a byte from the DAC.WriteDSP &H20ReadDAC% = ReadDSP%END FUNCTIONFUNCTION ReadDSP%WAIT (Baseport% + &HE), &H80: 'wait for bit 7 on pollportDO: DSPIn% = INP(Baseport% + 10): LOOP UNTIL DSPIn% <> &HAAReadDSP% = DSPIn%END FUNCTIONFUNCTION ResetDSP%ct = 0: stat = 0: ready = &HAAResetPort?? = Baseport% + &H6OUT ResetPort??, 1! MOV DX, ResetPort??! IN AL,DX! IN AL,DX! IN AL,DX! IN AL,DX! IN AL,DX! IN AL,DXDOOUT Baseport% + &H6, 0stat = INP(Baseport% + &HE)stat = INP(Baseport% + &HA)IF stat = ready THEN EXIT DOINCR ctLOOP WHILE ct < 200 'wait about 100 msIF stat = ready THEN ResetDSP% = 1 ELSE ResetDSP% = 0END FUNCTIONSUB SpeakerState (OnOff%)' Turns speaker on or off.IF OnOff% THEN WriteDSP &HD1 ELSE WriteDSP &HD3END SUBSUB VocVolume (Right1%, Left1%, Getvol%)OUT Baseport% + 4, &H4IF Getvol% THENLeft1% = INP(Baseport% + 5) \ 16Right1% = INP(Baseport% + 5) AND &HFEXIT SUBELSEOUT Baseport% + 5, (Right1% + Left1% * 16) AND &HFFEND IFEND SUBSUB WriteDSP (Byte2%)' Writes a byte to the DSPDOA% = INP(Baseport% + 12) AND &H80LOOP WHILE A%OUT Baseport% + 12, Byte2%$IF 0! mov dx,wSBCBaseAddx ; SBC base I/O address 2x0h! add dl,0Ch ; Write-Buffer Status port, 2xChBusy:! in al,dx ; Read Write-Buffer Status port! or al,al ; Can write to DSP?! js Busy ; Bit 7 set, try again! mov al,bData ; Get DSP command or data! out dx,al ; Send to DSP$ENDIFEND SUBSUB GetArray(BYVAL InputFileHandle%,A&(),BYVAL ReadBytes??, BytesRead??)LOCAL IputFileHandle??InputFileHandle?? = FileAttr(InputFileHandle%,2)BufferSeg?? = VARSEG(A&(0))BufferOff?? = VARPTR(A&(0))'read file! push ds! mov ax, &h3F00! mov bx, InputFileHandle??! mov cx, ReadBytes??! mov dx, BufferOff??! mov ds, BufferSeg??! int &h21! LES BX, BytesRead??! mov ES:[BX], ax! pop dsEND SUB
Here is a Link to the file
RadioTelephoneTutor.com/PBDmaPlay.zip
I think this is the root of the problem.
In no way do I think that sound using Dmaplay would be resource
hungry. I even tested it out by droping the cycles to 300. Same result.
Buggy, Buggy Buggy.
I hope someone can get this fixed.
Conquer the FCC GROL, & Amatuer Radio test