Sound
Sound
Hello,
I think, that every OS should have routines to play sounds. (WAV, MOD, MP3 etc.). But Here is very big trouble. How to init your Sound Card? Of course OS is being write in 32 - bit PMode.
Does anyone know how to initialze every sound card which is compatible with Sound Blaster?
I know that I can download e.g. SBINIT.COM but then I must have different SBINIT to every Sound Blaster Card. I ask about universal Sound Blaster Driver like VBE (Vesa for Graphic Card) or how to init it using assembler.
Best Regards
Peter
I think, that every OS should have routines to play sounds. (WAV, MOD, MP3 etc.). But Here is very big trouble. How to init your Sound Card? Of course OS is being write in 32 - bit PMode.
Does anyone know how to initialze every sound card which is compatible with Sound Blaster?
I know that I can download e.g. SBINIT.COM but then I must have different SBINIT to every Sound Blaster Card. I ask about universal Sound Blaster Driver like VBE (Vesa for Graphic Card) or how to init it using assembler.
Best Regards
Peter
Re:Sound
Something like the Linux drivers for your sound card might be the best source of information like this; you're lucky if your sound card can emulate something standard like the Sound Blaster. But you're pretty much stuck if your sound card requires a proprietary init program even for Linux operation.
Re:Sound
For Soundblaster cards, check out Creative's opensource section:
http://opensource.creative.com/
Hope that helps,
K.J.
http://opensource.creative.com/
Hope that helps,
K.J.
Re:Sound
Programming for the internal speaker is not that bad. Building drivers for sound cards will drive you to drink. It's been awhile since I've worked on it, so perhaps there is more standardization now and better references, but frankly I doubt it.Tommy wrote: Is sound something hard to program into your OS? I haven't gotten there yet...
I'm still trying to set up the GDT and switch to PMode! My computer keeps restarting every time I do?!
Re:Sound
Once up on a time, I tried to write a MIDI-player in plain assembler. Okey, I never got the player to work, but I found this BASIC-code under the coding time:
; SBDetected = 0
; FOR port = &H210 TO &H280 STEP &H10
; OUT port + &H6, 1
; FOR Count = 1 TO 100
; OUT port + &H6, 0
; Stat = INP(port + &HE)
; Stat = INP(port + &HA)
; IF Stat = &HAA THEN EXIT FOR
; NEXT Count
; IF Stat = &HAA THEN SBDetected = 1: BasePort = port: EXIT FOR
; NEXT port
; IF SBDetected = 0 THEN
; PRINT "Sorry, this program requires a SoundBlaster compatible sound card!"
; PRINT : END
; END IF
So I wrote a likely routine in assembler:
FM.Init:
Pusha
Mov CX, 0x200
FM.InitLoop1:
Add CX, 0x10
Mov DX, CX
Add DX, 0x6
Mov AL, 1
Out DX, AL
Mov BH, 0
FM.InitLoop2:
Inc BH
Mov DX, CX
Add DX, 0x6
Mov AL, 0
Out DX, AL
Mov DX, CX
Add DX, 0xE
In AL, DX
Mov DX, CX
Add DX, 0xA
In AL, DX
Cmp AL, 0xAA
Je FM.InitLoop2Done
Cmp BH, 100
Jne FM.InitLoop2
Jmp FM.InitLoop2Done2
FM.InitLoop2Done:
Mov Word [FM.BasePort], CX
Mov CX, 0x280
FM.InitLoop2Done2:
Cmp CX, 0x280
Jne FM.InitLoop1
Popa
Ret
And that code worked for me, maybe it'll work for you. Remember that it only finds SoundBlaster compatible sound cards and it's baseadress.
Best Regards
// Christopher Vigren
; SBDetected = 0
; FOR port = &H210 TO &H280 STEP &H10
; OUT port + &H6, 1
; FOR Count = 1 TO 100
; OUT port + &H6, 0
; Stat = INP(port + &HE)
; Stat = INP(port + &HA)
; IF Stat = &HAA THEN EXIT FOR
; NEXT Count
; IF Stat = &HAA THEN SBDetected = 1: BasePort = port: EXIT FOR
; NEXT port
; IF SBDetected = 0 THEN
; PRINT "Sorry, this program requires a SoundBlaster compatible sound card!"
; PRINT : END
; END IF
So I wrote a likely routine in assembler:
FM.Init:
Pusha
Mov CX, 0x200
FM.InitLoop1:
Add CX, 0x10
Mov DX, CX
Add DX, 0x6
Mov AL, 1
Out DX, AL
Mov BH, 0
FM.InitLoop2:
Inc BH
Mov DX, CX
Add DX, 0x6
Mov AL, 0
Out DX, AL
Mov DX, CX
Add DX, 0xE
In AL, DX
Mov DX, CX
Add DX, 0xA
In AL, DX
Cmp AL, 0xAA
Je FM.InitLoop2Done
Cmp BH, 100
Jne FM.InitLoop2
Jmp FM.InitLoop2Done2
FM.InitLoop2Done:
Mov Word [FM.BasePort], CX
Mov CX, 0x280
FM.InitLoop2Done2:
Cmp CX, 0x280
Jne FM.InitLoop1
Popa
Ret
And that code worked for me, maybe it'll work for you. Remember that it only finds SoundBlaster compatible sound cards and it's baseadress.
Best Regards
// Christopher Vigren
Re:Sound
Now that I think about it, lots of BASIC programs have soundblaster routines in them. Check out:
http://www.allbasiccode.com/
To find some(UGH! I still can't believe how bad a job whoever took over that site did with the design and color choices).
K.J.
http://www.allbasiccode.com/
To find some(UGH! I still can't believe how bad a job whoever took over that site did with the design and color choices).
K.J.
Re:Sound
I just finished a little experiment in which a sound is played during kernel setup (sort of like displaying a message. What I was actually shooting for was a barebones implementation. I'm going to share here basically what I did for this.
First of all, I found a tiny WAV file. Then I wrote a small C program to read the size of the data from the header, then strip out the header by writing the data to another file. This isn't actually necessary, but I just wanted the raw sample data to read off a floppy into a specific spot in memory
//--------------------------------------------
FILE *fp;
FILE *out;
char data[4096]; // bigger than WAV file
int data_size[1];
if( !(fp = fopen( "in.wav", "r" )))
exit(0);
if( !(out = fopen( "out.wav", "w" )))
exit(0);
fseek( fp, 40, 0 );
fread( data_size, sizeof(int), 1, fp);
fread( data, sizeof(char), *data_size, fp);
fwrite( data, sizeof(char), *data_size, out);
fclose( fp );
fclose( out );
//--------------------------------------------
Then I used partcopy to put in on the floppy after the setup code (which in this case was two sectors after the boot sector). My stripped file was 678 bytes long.
partcopy out.wav 0 678 -f0 600
Within the boot loader, I read four sectors off the floppy into a particular spot in memory (0x1300). Four sectors was enough to get all of the 678 bytes of data.
//--------------------------------------------
mov bx, 0x1300 ; destination offset
mov al, 4 ; number of sectors to read
mov cl, 4 ; sector start
call read_sectors
read_sectors:
mov ah, 0x02 ; read sectors function
mov ch, 0 ; cylinder 0
mov dl, [bootdrv] ; drive number
mov dh, 0 ; head number
int 0x13 ; call bios disk i/o
jc read_sectors
mov dx,0x3f2 ; Turn off floppy motor
mov al,0x0c
out dx,al
ret
//--------------------------------------------
Now that I had sound samples at a particular spot in memory, I needed to set up my SB-compatible sound card, the DMA for transferring the data from memory, and write an ISR for responding to the interrupt the sound card will generate when it's finished processing the data.
The base port for SB could be anywhere from 0x220 - 0x280. I was lucky. It was 0x220. Once you have the base port, the other ports are relative to it. The way you detect a SB-compatible DSP chip is to reset by writing "1" to the Reset port (base + 0x06), waiting, then writing "0" to it. Then you poll bit 7 in the Read-Buffer Status port (base + 0x0E) until it's set. Finally you read a byte from the Read Data port (base + 0x0A). If that byte is 0xAA, then you're all set. Otherwise, you have to try a different base port or you don't have an SB-compatible chip. If the following code is a bit cryptic, sorry. I didn't clean it up.
//--------------------------------------------
mov dx, 0x220 ; base port
add dx, 0x06
mov al, 1
out dx, al
sub al, al
waitloop:
dec al
jnz waitloop
out dx, al
xor cx, cx
add dl, 8 ; 0xE
nodata:
in al, dx
or al, al
jns again
sub dl, 4 ; 0xA
in al, dx
jmp finis
again:
loop nodata
finis:
mov [reg32], eax ; show the byte read
call printreg32 ; handle error here
//--------------------------------------------
In my case, when I ran this much, I saw the 000000AA on the screen, so I knew I was good to proceed. Once the DSP has been reset like this, you can write and read from it. I wrote a macro to simplify the many calls I would make.
;--------------------------------------------
%macro DSP_WRITE 1
mov ah, byte %1
call write_dsp
%endmacro
;--------------------------------------------
Heres the actual routine for writing a byte to the DSP. You keep checking the Write Status port (base + 0x0C) until bit 7 is clear, then you send the byte to the same port
;--------------------------------------------
write_dsp:
push dx
mov edx, 0x220
add dx, 0x0C
@write_busy:
in al, dx
or al, al ; ALSO and al, 0X80 jnz @busy
js @write_busy
mov al, ah ; AH contains byte to write
out dx, al
pop dx
ret
;--------------------------------------------
Here's a series of commands for the DSP.
;--------------------------------------------
DSP_WRITE 0x40 ; set sample rate
DSP_WRITE 165 ; 11025 Hz ( 256 - (1000000/rate))
DSP_WRITE 0x41 ; enable speaker
DSP_WRITE 0xD0 ; pause 8-bit DMA
DSP_WRITE 0xD5 ; pause 16-bit DMA
;--------------------------------------------
Then I was ready to set up the DMA. Oops, I forget to say that I set up a ISR for IRQ5 (which I knew was the interrupt from my control settings in NT).
First of all, I found a tiny WAV file. Then I wrote a small C program to read the size of the data from the header, then strip out the header by writing the data to another file. This isn't actually necessary, but I just wanted the raw sample data to read off a floppy into a specific spot in memory
//--------------------------------------------
FILE *fp;
FILE *out;
char data[4096]; // bigger than WAV file
int data_size[1];
if( !(fp = fopen( "in.wav", "r" )))
exit(0);
if( !(out = fopen( "out.wav", "w" )))
exit(0);
fseek( fp, 40, 0 );
fread( data_size, sizeof(int), 1, fp);
fread( data, sizeof(char), *data_size, fp);
fwrite( data, sizeof(char), *data_size, out);
fclose( fp );
fclose( out );
//--------------------------------------------
Then I used partcopy to put in on the floppy after the setup code (which in this case was two sectors after the boot sector). My stripped file was 678 bytes long.
partcopy out.wav 0 678 -f0 600
Within the boot loader, I read four sectors off the floppy into a particular spot in memory (0x1300). Four sectors was enough to get all of the 678 bytes of data.
//--------------------------------------------
mov bx, 0x1300 ; destination offset
mov al, 4 ; number of sectors to read
mov cl, 4 ; sector start
call read_sectors
read_sectors:
mov ah, 0x02 ; read sectors function
mov ch, 0 ; cylinder 0
mov dl, [bootdrv] ; drive number
mov dh, 0 ; head number
int 0x13 ; call bios disk i/o
jc read_sectors
mov dx,0x3f2 ; Turn off floppy motor
mov al,0x0c
out dx,al
ret
//--------------------------------------------
Now that I had sound samples at a particular spot in memory, I needed to set up my SB-compatible sound card, the DMA for transferring the data from memory, and write an ISR for responding to the interrupt the sound card will generate when it's finished processing the data.
The base port for SB could be anywhere from 0x220 - 0x280. I was lucky. It was 0x220. Once you have the base port, the other ports are relative to it. The way you detect a SB-compatible DSP chip is to reset by writing "1" to the Reset port (base + 0x06), waiting, then writing "0" to it. Then you poll bit 7 in the Read-Buffer Status port (base + 0x0E) until it's set. Finally you read a byte from the Read Data port (base + 0x0A). If that byte is 0xAA, then you're all set. Otherwise, you have to try a different base port or you don't have an SB-compatible chip. If the following code is a bit cryptic, sorry. I didn't clean it up.
//--------------------------------------------
mov dx, 0x220 ; base port
add dx, 0x06
mov al, 1
out dx, al
sub al, al
waitloop:
dec al
jnz waitloop
out dx, al
xor cx, cx
add dl, 8 ; 0xE
nodata:
in al, dx
or al, al
jns again
sub dl, 4 ; 0xA
in al, dx
jmp finis
again:
loop nodata
finis:
mov [reg32], eax ; show the byte read
call printreg32 ; handle error here
//--------------------------------------------
In my case, when I ran this much, I saw the 000000AA on the screen, so I knew I was good to proceed. Once the DSP has been reset like this, you can write and read from it. I wrote a macro to simplify the many calls I would make.
;--------------------------------------------
%macro DSP_WRITE 1
mov ah, byte %1
call write_dsp
%endmacro
;--------------------------------------------
Heres the actual routine for writing a byte to the DSP. You keep checking the Write Status port (base + 0x0C) until bit 7 is clear, then you send the byte to the same port
;--------------------------------------------
write_dsp:
push dx
mov edx, 0x220
add dx, 0x0C
@write_busy:
in al, dx
or al, al ; ALSO and al, 0X80 jnz @busy
js @write_busy
mov al, ah ; AH contains byte to write
out dx, al
pop dx
ret
;--------------------------------------------
Here's a series of commands for the DSP.
;--------------------------------------------
DSP_WRITE 0x40 ; set sample rate
DSP_WRITE 165 ; 11025 Hz ( 256 - (1000000/rate))
DSP_WRITE 0x41 ; enable speaker
DSP_WRITE 0xD0 ; pause 8-bit DMA
DSP_WRITE 0xD5 ; pause 16-bit DMA
;--------------------------------------------
Then I was ready to set up the DMA. Oops, I forget to say that I set up a ISR for IRQ5 (which I knew was the interrupt from my control settings in NT).
Re:Sound
;--------------------------------------------
dsp_isr:
???push ax
???push dx
???
???mov???edx,0x220
???add???edx,0x0E
???in???al,dx
???mov???eax,0x20
???out???0x20,al
???
???pop dx
???pop ax
???iret
;--------------------------------------------
Here's the DMA setup.
;--------------------------------------------
???mov???eax,1??????; mask out the DMA channel while we reprogram it
???add???eax,4
???out???0x0a,al
???xor???eax,eax??????; clear byte pointer flip-flop
???out???0x0c,al
???mov???eax,01001001b??????; mode
???out???0x0b,al
???
???mov edx, 1??????; channel
???shl edx, 1??????; trick to get address port from channel #
???
???mov ax, 0x1300???; FIXME hardcoded offset
???out dx, al???;
???mov al, ah???; loaded in two stages
???out dx, al
???
???inc edx??????; set the size (length - 1)
???mov ax, 0x677???; FIXME hardcoded length
???out dx, al???;
???mov al, ah???; loaded in two stages
???out dx, al
???
???mov al, 0???; page=0
???out 0x83, al???; 8-bit Page Register for Channel 1
???mov???eax,1??????; unmask the DMA channel 1
???out???0x0a,al
;--------------------------------------------
Then, I was ready to tell the DSP to get funky:
;--------------------------------------------
???DSP_WRITE 0x14???; start 8-bit DMA transfer
???DSP_WRITE 0x77???; low byte of (length - 1)
???DSP_WRITE 0x06???; high byte of (length - 1)
???
;--------------------------------------------
That's it! It worked the first time out. On my machine. YMMV...a lot.
dsp_isr:
???push ax
???push dx
???
???mov???edx,0x220
???add???edx,0x0E
???in???al,dx
???mov???eax,0x20
???out???0x20,al
???
???pop dx
???pop ax
???iret
;--------------------------------------------
Here's the DMA setup.
;--------------------------------------------
???mov???eax,1??????; mask out the DMA channel while we reprogram it
???add???eax,4
???out???0x0a,al
???xor???eax,eax??????; clear byte pointer flip-flop
???out???0x0c,al
???mov???eax,01001001b??????; mode
???out???0x0b,al
???
???mov edx, 1??????; channel
???shl edx, 1??????; trick to get address port from channel #
???
???mov ax, 0x1300???; FIXME hardcoded offset
???out dx, al???;
???mov al, ah???; loaded in two stages
???out dx, al
???
???inc edx??????; set the size (length - 1)
???mov ax, 0x677???; FIXME hardcoded length
???out dx, al???;
???mov al, ah???; loaded in two stages
???out dx, al
???
???mov al, 0???; page=0
???out 0x83, al???; 8-bit Page Register for Channel 1
???mov???eax,1??????; unmask the DMA channel 1
???out???0x0a,al
;--------------------------------------------
Then, I was ready to tell the DSP to get funky:
;--------------------------------------------
???DSP_WRITE 0x14???; start 8-bit DMA transfer
???DSP_WRITE 0x77???; low byte of (length - 1)
???DSP_WRITE 0x06???; high byte of (length - 1)
???
;--------------------------------------------
That's it! It worked the first time out. On my machine. YMMV...a lot.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Sound
modern chipsets (including mine seems to have builtin AC97 sound chip. Did anyone here already has some code for that chip ?
Re:Sound
I think if someone coughed up a comparable minimal implementation using something like PCI DMA and AC97, it would be a welcome contribution.
My crusty old example suits my aging hardware setup. My interests tend toward lower bandwidth solutions, so I'm not likely to go buy any new hardware any time soon.
My crusty old example suits my aging hardware setup. My interests tend toward lower bandwidth solutions, so I'm not likely to go buy any new hardware any time soon.