/programs/ac97wav/trunk/ac97.inc |
---|
0,0 → 1,288 |
; Vendor ids |
INTEL_VID = 0x8086 |
SIS_VID = 0x1039 |
NVIDIA_VID = 0x10DE |
AMD_VID = 0x1022 |
; Device ids |
ICH_DID = 0x2415 |
ICH0_DID = 0x2425 |
ICH2_DID = 0x2445 |
ICH3_DID = 0x2485 |
ICH4_DID = 0x24C5 |
ICH5_DID = 0x24D5 |
MX440_DID = 0x7195 |
SI7012_DID = 0x7012 |
NFORCE_DID = 0x01B1 |
NFORCE2_DID = 0x006A |
AMD8111_DID = 0x764D |
AMD768_DID = 0x7445 |
NAMBAR_REG = 0x10 ; native audio mixer BAR |
NAM_SIZE = 256 ; 256 bytes required. |
NABMBAR_REG = 0x14 ; native audio bus mastering BAR |
NABM_SIZE = 64 ; 64 bytes |
IRQ_REG = 0x3c ; IRQ holder for PCI |
INT_REG = 0x3d ; INT pin |
ICH4_CFG_REG = 0x41 ; ICH4 config register |
; BUS master registers, accessed via NABMBAR+offset |
; ICH supports 3 different types of register sets for three types of things |
; it can do, thus: |
; |
; PCM in (for recording) aka PI |
; PCM out (for playback) aka PO |
; MIC in (for recording) aka MC |
PI_BDBAR_REG = 0 ; PCM in buffer descriptor BAR |
PO_BDBAR_REG = 10h ; PCM out buffer descriptor BAR |
MC_BDBAR_REG = 20h ; MIC in buffer descriptor BAR |
; each buffer descriptor BAR holds a pointer which has entries to the buffer |
; contents of the .WAV file we're going to play. Each entry is 8 bytes long |
; (more on that later) and can contain 32 entries total, so each BAR is |
; 256 bytes in length, thus: |
BDL_SIZE = 32*8 ; Buffer Descriptor List size |
INDEX_MASK = 31 ; indexes must be 0-31 |
PI_CIV_REG = 4 ; PCM in current Index value (RO) |
PO_CIV_REG = 14h ; PCM out current Index value (RO) |
MC_CIV_REG = 24h ; MIC in current Index value (RO) |
;8bit read only |
; each current index value is simply a pointer showing us which buffer |
; (0-31) the codec is currently processing. Once this counter hits 31, it |
; wraps back to 0. |
; this can be handy to know, as once it hits 31, we're almost out of data to |
; play back or room to record! |
PI_LVI_REG = 5 ; PCM in Last Valid Index |
PO_LVI_REG = 15h ; PCM out Last Valid Index |
MC_LVI_REG = 25h ; MIC in Last Valid Index |
;8bit read/write |
; The Last Valid Index is a number (0-31) to let the codec know what buffer |
; number to stop on after processing. It could be very nasty to play audio |
; from buffers that aren't filled with the audio we want to play. |
PI_SR_REG = 6 ; PCM in Status register |
PO_SR_REG = 16h ; PCM out Status register |
MC_SR_REG = 26h ; MIC in Status register |
;16bit read/write |
; status registers. Bitfields follow: |
FIFO_ERR = BIT4 ; FIFO Over/Underrun W1TC. |
BCIS = BIT3 ; buffer completion interrupt status. |
; Set whenever the last sample in ANY |
; buffer is finished. Bit is only |
; set when the Interrupt on Complete |
; (BIT4 of control reg) is set. |
LVBCI = BIT2 ; Set whenever the codec has processed |
; the last buffer in the buffer list. |
; Will fire an interrupt if IOC bit is |
; set. Probably set after the last |
; sample in the last buffer is |
; processed. W1TC |
CELV = BIT1 ; Current buffer == last valid. |
; Bit is RO and remains set until LVI is |
; cleared. Probably set up the start |
; of processing for the last buffer. |
DCH = BIT0 ; DMA controller halted. |
; set whenever audio stream is stopped |
; or something else goes wrong. |
PI_PICB_REG = 8 ; PCM in position in current buffer(RO) |
PO_PICB_REG = 18h ; PCM out position in current buffer(RO) |
MC_PICB_REG = 28h ; MIC in position in current buffer (RO) |
;16bit read only |
; position in current buffer regs show the number of dwords left to be |
; processed in the current buffer. |
; |
PI_PIV_REG = 0ah ; PCM in Prefected index value |
PO_PIV_REG = 1ah ; PCM out Prefected index value |
MC_PIV_REG = 2ah ; MIC in Prefected index value |
;8bit, read only |
; Prefetched index value register. |
; tells which buffer number (0-31) has be prefetched. I'd imagine this |
; value follows the current index value fairly closely. (CIV+1) |
; |
PI_CR_REG = 0bh ; PCM in Control Register |
PO_CR_REG = 1bh ; PCM out Control Register |
MC_CR_REG = 2bh ; MIC in Control Register |
; 8bit |
; Control register *MUST* only be accessed as an 8bit value. |
; Control register. See bitfields below. |
; |
IOCE = BIT4 ; interrupt on complete enable. |
; set this bit if you want an intrtpt |
; to fire whenever LVBCI is set. |
FEIFE = BIT3 ; set if you want an interrupt to fire |
; whenever there is a FIFO (over or |
; under) error. |
LVBIE = BIT2 ; last valid buffer interrupt enable. |
; set if you want an interrupt to fire |
; whenever the completion of the last |
; valid buffer. |
RR = BIT1 ; reset registers. Nukes all regs |
; except bits 4:2 of this register. |
; Only set this bit if BIT 0 is 0 |
RPBM = BIT0 ; Run/Pause |
; set this bit to start the codec! |
GLOB_CNT_REG = 2ch ; Global control register |
SEC_RES_EN = BIT5 ; secondary codec resume event |
; interrupt enable. Not used here. |
PRI_RES_EN = BIT4 ; ditto for primary. Not used here. |
ACLINK_OFF = BIT3 ; Turn off the AC97 link |
ACWARM_RESET = BIT2 ; Awaken the AC97 link from sleep. |
; registers preserved, bit self clears |
ACCOLD_RESET = BIT1 ; Reset everything in the AC97 and |
; reset all registers. Not self clearin |
;g |
GPIIE = BIT0 ; GPI Interrupt enable. |
; set if you want an interrupt to |
; fire upon ANY of the bits in the |
; GPI (general pursose inputs?) not used |
;. |
GLOB_STS_REG = 30h ; Global Status register (RO) |
MD3 = BIT17 ; modem powerdown status (yawn) |
AD3 = BIT16 ; Audio powerdown status (yawn) |
RD_COMPLETE_STS = BIT15 ; Codec read timed out. 0=normal |
BIT3SLOT12 = BIT14 ; shadowed status of bit 3 in slot 12 |
BIT2SLOT12 = BIT13 ; shadowed status of bit 2 in slot 12 |
BIT1SLOT12 = BIT12 ; shadowed status of bit 1 in slot 12 |
SEC_RESUME_STS = BIT11 ; secondary codec has resumed (and irqed) |
PRI_RESUME_STS = BIT10 ; primary codec has resumed (and irqed) |
SEC_CODEC_RDY = BIT9 ; secondary codec is ready for action |
PRI_CODEC_RDY = BIT8 ; Primary codec is ready for action |
; software must check these bits before |
; starting the codec! |
MIC_IN_IRQ = BIT7 ; MIC in caused an interrupt |
PCM_OUT_IRQ = BIT6 ; One of the PCM out channels IRQed |
PCM_IN_IRQ = BIT5 ; One of the PCM in channels IRQed |
MODEM_OUT_IRQ = BIT2 ; modem out channel IRQed |
MODEM_IN_IRQ = BIT1 ; modem in channel IRQed |
GPI_STS_CHANGE = BIT0 ; set whenever GPI's have changed. |
; BIT0 of slot 12 also reflects this. |
ACC_SEMA_REG = 34h ; Codec write semiphore register |
CODEC_BUSY = BIT0 ; codec register I/O is happening |
; self clearing |
; |
; Buffer Descriptors List |
; As stated earlier, each buffer descriptor list is a set of (up to) 32 |
; descriptors, each 8 bytes in length. Bytes 0-3 of a descriptor entry point |
; to a chunk of memory to either play from or record to. Bytes 4-7 of an |
; entry describe various control things detailed below. |
; |
; Buffer pointers must always be aligned on a Dword boundry. |
; |
; |
IOC = BIT31 ; Fire an interrupt whenever this |
; buffer is complete. |
BUP = BIT30 ; Buffer Underrun Policy. |
; if this buffer is the last buffer |
; in a playback, fill the remaining |
; samples with 0 (silence) or not. |
; It's a good idea to set this to 1 |
; for the last buffer in playback, |
; otherwise you're likely to get a lot |
; of noise at the end of the sound. |
; |
; Bits 15:0 contain the length of the buffer, in number of samples, which |
; are 16 bits each, coupled in left and right pairs, or 32bits each. |
; Luckily for us, that's the same format as .wav files. |
; |
; A value of FFFF is 65536 samples. Running at 44.1Khz, that's just about |
; 1.5 seconds of sample time. FFFF * 32bits is 1FFFFh bytes or 128k of data. |
; |
; A value of 0 in these bits means play no samples. |
; |
;***************************************************************************** |
;* AC97 Codec registers include (based on Jeff Leyda AC97 wav player SDK :-) |
;***************************************************************************** |
; Not all codecs are created =al. Refer to the spec for your specific codec. |
; All registers are 16bits wide. Access to codec registers over the AC97 link |
; is defined by the OEM. |
; Secondary codec's are accessed by ORing in BIT7 of all register accesses. |
; each codec/mixer register is 16bits |
CODEC_RESET_REG = 00 ; reset codec |
CODEC_MASTER_VOL_REG = 02 ; master volume |
CODEC_HP_VOL_REG = 04 ; headphone volume |
CODEC_MASTER_MONO_VOL_REG = 06 ; master mono volume |
CODEC_MASTER_TONE_REG = 08 ; master tone (R+L) |
CODEC_PCBEEP_VOL_REG = 0ah ; PC beep volume |
CODEC_PHONE_VOL_REG = 0ch ; phone volume |
CODEC_MIC_VOL_REG = 0eh ; MIC volume |
CODEC_LINE_IN_VOL_REG = 10h ; line input volume |
CODEC_CD_VOL_REG = 12h ; CD volume |
CODEC_VID_VOL_REG = 14h ; video volume |
CODEC_AUX_VOL_REG = 16h ; aux volume |
CODEC_PCM_OUT_REG = 18h ; PCM output volume |
CODEC_RECORD_SELECT_REG = 1ah ; record select input |
CODEC_RECORD_VOL_REG = 1ch ; record volume |
CODEC_RECORD_MIC_VOL_REG = 1eh ; record mic volume |
CODEC_GP_REG = 20h ; general purpose |
CODEC_3D_CONTROL_REG = 22h ; 3D control |
; 24h is reserved |
CODEC_POWER_CTRL_REG = 26h ; powerdown control |
CODEC_EXT_AUDIO_REG = 28h ; extended audio |
CODEC_EXT_AUDIO_CTRL_REG = 2ah ; extended audio control |
CODEC_PCM_FRONT_DACRATE_REG = 2ch ; PCM out sample rate |
CODEC_PCM_SURND_DACRATE_REG = 2eh ; surround sound sample rate |
CODEC_PCM_LFE_DACRATE_REG = 30h ; LFE sample rate |
CODEC_LR_ADCRATE_REG = 32h ; PCM in sample rate |
CODEC_MIC_ADCRATE_REG = 34h ; mic in sample rate |
; registers 36-7a are reserved on the ICH |
CODEC_VENDORID1_REG = 7ch ; codec vendor ID 1 |
CODEC_VENDORID2_REG = 7eh ; codec vendor ID 2 |
; When 2 codecs are present in the system, use BIT7 to access the 2nd |
; set of registers, ie 80h-feh |
SECONDARY_CODEC = BIT7 ; 80-8f registers for 2nda |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
/programs/ac97wav/trunk/ac97wav.asm |
---|
0,0 → 1,1084 |
;--------------------------------------------------------------------- |
; |
; MenuetOS AC97 WAV Player |
; |
; 0.03 November 10, 2004 doesn't halt if file not found |
; 0.04 November 11, 2004 better positioning (with mouse) |
; 0.05 November 14, 2004 internals clean up |
; fixed cutting sound at the edges |
; 0.06 November 17, 2004 fixed many bugs |
; 0.07 Nov 20, 2004 deactivates text box when 'play' pressed |
; stops playing before closing a window |
; 0.08 Nov 24, 2004 added support for 8bit and mono modes |
; +variable rate for some chipsets |
; |
; Use [flat assembler 1.56] to compile. |
; |
;--------------------------------------------------------------------- |
use32 ; turn on 32 bit mode |
org 0x0 ; the program is placed at 0 offset |
db 'MENUET01' ; 8-byte identifier of MenuetOS application |
dd 0x01 ; header version (always 1) |
dd START ; address of the beginning of the code |
dd IMAGE_END ; size of the program's image |
dd MEMORY_END ; how much memory does it need |
dd STACK_P ; a pointer to the top of the stack |
dd textbox_string |
; dd 0x0 ; address of buffer for parameters (not used) |
dd 0x0 ; reserved |
;--------------------------------------------------------------------- |
include "lang.inc" |
include "macros.inc" ; standart macros & constants |
include "meosfunc.inc" ; MenuetOS API functions names |
include "debug.inc" ; printing to debug board |
include "constant.inc" ; BIT?? constants |
include "ac97.inc" ; AC'97 constants |
include "pci.inc" ; PCI interface |
include "codec.inc" ; functions for configuring codec |
include "frontend.inc" ; main window |
;--------------------------------------------------------------------- |
; Uncomment these strings if you don't want to receive debug messages: |
; macro dps str {} ; dps prints a string without CRLF |
; macro dpd num {} ; prints unsigned decimal number |
; macro pregs {} ; outputs EAX, EBX, ECX, EDX |
; macro newline {} ; CRLF |
; macro print str {} ; output a string with CRLF |
; macro dph arg {} ; print hex number |
;--------------------------------------------------------------------- |
;macro device id, addr { dd id, addr } |
macro devices [id, str] |
{ |
common |
label supported_devices dword |
forward |
local string |
dd id |
dd string |
forward |
string db str |
db 0 |
} |
devices \ |
(ICH_DID shl 16) + INTEL_VID, "ICH" ,\ |
(ICH0_DID shl 16) + INTEL_VID, "ICH0" ,\ |
(ICH2_DID shl 16) + INTEL_VID, "ICH2" ,\ |
(ICH3_DID shl 16) + INTEL_VID, "ICH2" ,\ |
(ICH4_DID shl 16) + INTEL_VID, "ICH4" ,\ |
(ICH5_DID shl 16) + INTEL_VID, "ICH5" ,\ |
(MX440_DID shl 16) + INTEL_VID, "440MX" ,\ |
(SI7012_DID shl 16) + SIS_VID, "SI7012" ,\ |
(NFORCE_DID shl 16) + NVIDIA_VID, "NForce" ,\ |
(NFORCE2_DID shl 16) + NVIDIA_VID, "NForce2",\ |
(AMD8111_DID shl 16) + AMD_VID, "AMD8111",\ |
(AMD768_DID shl 16) + AMD_VID, "AMD768" |
dd 0 |
;--------------------------------------------------------------------- |
;--- MAIN PROGRAM -------------------------------------------------- |
;--------------------------------------------------------------------- |
START: |
; Print PCI version (for example, 2.16) |
; mcall MF_PCI, 0 |
; mov bl, al |
; movzx eax, ah |
; dps "PCI version: " |
; dpd eax |
; movzx eax, bl |
; dpd eax |
; newline |
; Check PCI access mechanism (must be 1 or 2) |
mcall MF_PCI, 2 |
dec al |
cmp al, 1 |
jna @f |
print "Error: cannot access PCI bus." |
jmp exit |
; dps "PCI returned " |
; movzx eax, al |
; dpd eax |
; newline |
@@: |
; Get last bus & then check all buses & devices |
mcall MF_PCI, 1 |
mov [lastbus], al |
; looking for a compatible device |
mov [bus], -1 |
.next_bus: |
inc [bus] |
mov al, [lastbus] |
cmp al, [bus] |
jb .device_not_found |
mov [devfn], 0 |
.next_devfn: |
mov cl, 0 |
call pciRegRead32 |
mov edi, supported_devices |
@@: |
mov ebx, [edi] |
test ebx, ebx |
jz @f |
cmp eax, ebx |
jnz .skip |
add edi, 4 |
mov [device_id], eax |
mov edx, [edi] |
call debug_outstr |
jmp proceed |
.skip: |
add edi, 8 |
jmp @b |
@@: |
inc [devfn] |
cmp [devfn], 255 |
jb .next_devfn |
jmp .next_bus |
.device_not_found: |
print "Could not find Intel AC'97 compatible codec!" |
print "1) Check if it's enabled in BIOS." |
print "2) Check if your device is included in the device list." |
jmp exit |
proceed: |
print " integrated AC97 audio codec detected." |
mov eax, [device_id] |
cmp eax, (ICH4_DID shl 16) + INTEL_VID |
je .newich |
cmp eax, (ICH5_DID shl 16) + INTEL_VID |
jne .nonewich |
.newich: |
mov [AC97ICH4], 1 |
.nonewich: |
cmp eax, (SI7012_DID shl 16) + SIS_VID |
jne @f |
mov [SI7012], 1 |
@@: |
;--------------------------------------------------------------------- |
; Get NAMBAR register base port address & save it |
mov cl, NAMBAR_REG |
call pciRegRead16 |
and eax, 0xFFFE |
mov [NAMBAR], ax |
test eax, eax |
jnz .mixer_base_ok |
print "Error: Intel ICH based AC97 audio codec disabled in BIOS!" |
jmp exit |
.mixer_base_ok: |
dps "NAMBAR: " |
dph eax |
; Get NABMBAR & save it |
mov cl, NABMBAR_REG |
call pciRegRead16 |
and eax, 0xFFC0 |
mov [NABMBAR], ax |
test eax, eax |
jnz .bm_base_ok |
print "Error: Intel ICH based AC97 audio codec disabled in BIOS!" |
jmp exit |
.bm_base_ok: |
dps " NABMBAR: " |
dph eax |
newline |
;--------------------------------------------------------------------- |
; Get IRQ (not used) |
mov cl, IRQ_REG |
call pciRegRead8 |
mov [AC97IRQ], al |
; Get Interrupt pin (not used) |
mov cl, INT_REG |
call pciRegRead8 |
mov [AC97INT], al |
; AC97ICH4 should work then... |
cmp [AC97ICH4], 1 |
jne .skip_ich4_init |
mov cl, ICH4_CFG_REG ; 0x41 |
call pciRegRead8 |
or al, 0x1 |
mov dl, al |
call pciRegWrite8 |
mov cl, 0x54 |
call pciRegRead16 |
and eax, 0xFFFF |
dps "Power Control & Status: " |
dph eax |
newline |
.skip_ich4_init: |
;--------------------------------------------------------------------- |
mov cl, PCI_CMD_REG |
call pciRegRead16 ; read PCI command register |
mov dx, ax |
or dx, IO_ENA+BM_ENA+BIT10 ; enable IO and bus master + disable |
; interrupts |
call pciRegWrite16 |
;--------------------------------------------------------------------- |
print "Enabling access to ports..." |
movzx ecx, [NAMBAR] |
mov edx, ecx |
add edx, NAM_SIZE |
mcall MF_PORTS, PRT_RESERVE |
test eax, eax |
jz @f |
print "Error: couldn't enable access to ports" |
jmp exit |
@@: |
movzx ecx, [NABMBAR] |
mov edx, ecx |
add edx, NABM_SIZE |
mcall MF_PORTS, PRT_RESERVE |
test eax, eax |
jz @f |
print "Error: couldn't enable access to ports" |
jmp exit |
@@: |
;--------------------------------------------------------------------- |
; setup the Codec |
mov eax, 48000 |
call codecConfig ; unmute codec, set rates. |
test eax, eax |
jnz @f |
print "Error: cannot initialize AC97 device." |
jmp fpexit |
@@: |
print "Congrutalations! Your device has been initialized properly!" |
call print_info |
;--------------------------------------------------------------------- |
; register reset the DMA engine. |
mov edx, PO_CR_REG ; PCM out control register |
mov al, RR ; reset |
call NABMBAR_write_byte |
;start fix for MM (1) |
mcall MF_INTERNAL_SERVICES,ALLOC_PHYS_MEM,120*1024 |
test eax,eax |
jz no_phys_buffers ;not enough memory |
mov [phys_wav_buffer1],eax |
add eax,60*1024 |
mov [phys_wav_buffer2],eax |
mcall MF_INTERNAL_SERVICES,ALLOC_PHYS_MEM,32*8 |
test eax,eax |
jnz @f |
mcall MF_INTERNAL_SERVICES,FREE_PHYS_MEM,[phys_wav_buffer1] |
jmp no_phys_buffers |
@@: |
mov [phys_bdl_buffer],eax |
;end fix for MM (1) |
; create Buffer Descriptors List |
call prepare_BDL |
; open player's window |
mcall MF_THREAD, THR_CREATE, thread, thread_stack |
; wait for command |
.new_check: |
cmp [status], ST_PLAY |
jne @f |
call play |
@@: |
cmp [status], ST_STOP |
jne @f |
call stop |
@@: |
cmp [status], ST_EXIT |
je stopexit |
mcall MF_DELAY, 10 |
jmp .new_check |
stopexit: |
call stop |
fpexit: |
; free ports |
movzx ecx, [NAMBAR] |
mov edx, ecx |
add edx, NAM_SIZE |
mcall MF_PORTS, PRT_FREE |
movzx ecx, [NABMBAR] |
mov edx, ecx |
add edx, NABM_SIZE |
mcall MF_PORTS, PRT_FREE |
;--------------------------------------------------------------------- |
;start fix for MM (2) |
mcall MF_INTERNAL_SERVICES,FREE_PHYS_MEM,[phys_bdl_buffer] |
mcall MF_INTERNAL_SERVICES,FREE_PHYS_MEM,[phys_wav_buffer1] |
;end fix for MM (2) |
exit: |
mcall MF_EXIT |
no_phys_buffers: |
print "allocation of physical buffers failed" |
jmp exit |
;--------------------------------------------------------------------- |
;--- FUNCTIONS ----------------------------------------------------- |
;--------------------------------------------------------------------- |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; prepare_BDL - initializes BUFFER DESCRIPTORS LIST |
prepare_BDL: |
mov ecx, 32 / 2 ; make 32 entries in BDL |
mov edi, BDL_BUFFER |
; call get_my_address |
mov ebx, 30*1024 |
cmp [SI7012], 1 |
jne @f |
add ebx, ebx |
@@: |
; set buf. desc. 0 to start of data file in memory |
push eax |
; add eax, WAV_BUFFER1 |
;start fix for MM (6) |
mov eax,[phys_wav_buffer1] |
;end fix for MM (6) |
stosd |
; set length to 60k samples. 1 sample is 16 bit or 2 bytes. |
mov eax, ebx ;60*1024 ; number of samples |
or eax, BUP |
stosd |
mov eax, [esp] |
; add eax, WAV_BUFFER2 |
;start fix for MM (7) |
mov eax,[phys_wav_buffer2] |
;end fix for MM (7) |
stosd |
mov eax, ebx ;60*1024 |
or eax, BUP |
stosd |
pop eax |
loop @b |
; tell the DMA engine where to find our list of Buffer Descriptors. |
; eax = base addr! |
;start fix for MM (3) |
;copy to physical memory |
mcall MF_INTERNAL_SERVICES,SET_PHYS_BUFFER,[phys_bdl_buffer],BDL_BUFFER,32*8 |
;physical address of bdl |
mov eax,[phys_bdl_buffer] |
;end fix for MM (3) |
mov edx, PO_BDBAR_REG |
; add eax, BDL_BUFFER |
call NABMBAR_write_dword |
ret |
;--------------------------------------------------------------------- |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; stop - stops current music |
;; in: nothing |
;; out: nothing |
stop: |
; print "STOP!" |
push eax edx |
mcall MF_DELAY, 10 |
mov edx, PO_CR_REG |
mov al, 0 |
call NABMBAR_write_byte |
cmp [status], ST_STOP |
jne .exit |
mov [status], ST_DONE |
.exit: |
pop edx eax |
ret |
;--------------------------------------------------------------------- |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; play - plays wav file! |
;; in: nothing |
;; out: nothing (but sound :) !corrupts registers! |
play: |
; at first, reset file |
mov [fileinfo.first_block], 0 |
mcall MF_SYSTREE, fileinfo ; load a block, returns error code in eax |
; and size of the file in ebx |
test eax, eax ; 0 - successful |
jz @f |
print "AC97: File not found!" |
mov [status], ST_STOP |
jmp .exit |
@@: |
shr ebx, 9 ; size_of_file / 512 = number_of_blocks |
mov [file_size], ebx |
mov al, [LOAD_BUFFER+32] ; bytes per sample |
dec al |
jz @f |
cmp al, 3 |
je @f |
sub al, [LOAD_BUFFER+22] ; channels |
add al, 2 |
@@: |
mov [wav_mode], al |
pusha |
movzx ebx,word [LOAD_BUFFER+24] |
mov eax,48000 |
xor edx,edx |
div ebx |
mov [difference_of_frequency],al |
; dph eax |
mov ecx,edx |
imul eax,ecx,10 |
xor edx,edx |
div ebx |
mov ecx,edx |
imul ecx,10 |
push eax |
mov eax,ecx |
xor edx,edx |
div ebx |
; dph eax |
cmp eax,5 |
jl .temp_15 |
pop eax |
; dph eax |
inc eax |
jmp .temp_16 |
.temp_15: |
pop eax |
.temp_16: |
mov [difference_of_frequency_1],al |
; dph eax |
xor edx,edx |
movzx ebx,[difference_of_frequency] |
imul ebx,10 |
add bl,[difference_of_frequency_1] |
mov [difference_of_frequency_2],bl |
; dph ebx |
popa |
movzx eax, word [LOAD_BUFFER+24] |
;dps "Freq: " |
;dpd eax |
;newline |
call set_sample_rate |
; change the last_valid_index to the (current_index-1) |
; the LVI register tells the DMA engine where to stop playing |
call updateLVI |
; if current index is odd, load buffer 1 then 0, jump to tuneLoop |
; if it is even, buffers 0 then 1; tuneLoop1 |
call getCurrentIndex |
and eax, BIT0 |
mov esi, eax |
push eax |
call update_next_buffer |
pop eax |
xor eax, 1 |
call update_next_buffer |
; start playing! |
mov edx, PO_CR_REG |
mov al, RPBM |
call NABMBAR_write_byte |
jmp [jumpto+esi*4] |
.tuneLoop: |
; wait while the current_index is even |
@@: |
; dps "a" |
mcall MF_DELAY, 7 |
call getCurrentIndex |
test al, BIT0 |
jz @b ; loop if not ready yet |
; print "fa" |
call updateLVI |
mov eax, 0 |
call update_next_buffer |
test al, al |
jnz .exit_wait |
cmp [status], ST_PLAY |
jne .exit |
test [volume], 0x10000000 ; test volume_changed bit |
je @f |
mov al, byte [volume] |
call setVolume |
and [volume], 0x0FFFFFFF ; clear vloume_changed bit |
@@: |
.tuneLoop1: |
@@: |
; dps "b" |
mcall MF_DELAY, 7 |
call getCurrentIndex |
test al, BIT0 |
jnz @b ; loop if not ready yet |
; print "fb" |
cmp [status], ST_PLAY |
jne .exit |
call updateLVI |
mov eax, 1 |
call update_next_buffer |
test al, al |
jnz .exit_wait |
jmp .tuneLoop |
.exit_wait: |
mcall MF_DELAY, 30 ; a little pause - let the player finish |
.exit: |
ret |
attempts db 0 |
buffers dd WAV_BUFFER1, WAV_BUFFER2 |
jumpto dd play.tuneLoop, play.tuneLoop1 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; update_first_buffer - load a chunk into the first buffer, increments offset |
;; in: eax = number - 0 or 1 |
;; out: error code, 0 - successful |
update_next_buffer: |
push esi edi |
movzx edx, byte [wav_mode] |
mov ecx, [blocks + edx * 4] |
mov [fileinfo.blocks], ecx |
mov esi, LOAD_BUFFER |
mov edi, [buffers+eax*4] |
push eax ;save buffer index |
start_attempts: |
mcall MF_SYSTREE, fileinfo |
test eax, eax |
jz @f |
cmp [attempts],100 |
je @f |
inc [attempts] |
jmp start_attempts |
dpd eax |
newline |
dpd [fileinfo.first_block] |
newline |
@@: |
; print " loaded!" |
push eax ebx edx |
mov eax,ecx |
xor edx,edx |
imul eax,10 |
movzx ebx,[difference_of_frequency_2] |
div ebx |
mov ecx,eax |
; mov ebx,10 |
; mov eax,edx |
; xor edx,edx |
; div ebx |
; cmp edx,5 |
; jb temp_12_7 |
; inc ecx |
; temp_12_7: |
cmp edx,0 |
je temp_12_7 |
inc ecx |
temp_12_7: |
pop edx ebx |
mov eax,[esp+4] ;restore buffer index |
add [fileinfo.first_block], ecx ; +60Kb |
call [convert + edx * 4] |
;start fix for MM (4) |
mov eax,[esp+4] ;restore buffer index |
test eax,not 1 |
jz .ok |
print "buffer index out of range" |
dpd eax |
jmp .ret |
.ok: |
push ebp |
mov ebp,[phys_wav_buffer1+eax*4] |
mov edi,[buffers+eax*4] |
mcall MF_INTERNAL_SERVICES,SET_PHYS_BUFFER,ebp,edi,60*1024 |
pop ebp |
.ret: |
pop eax |
add esp,4 ;pop buffer index |
;end fix for MM (4) |
pop edi esi |
ret |
c8mono: |
mov [type_of_conversion],1 |
jmp for_all_type |
c8mono_1: |
lodsb |
call c8mono_2 |
push ax |
shl eax,16 |
pop ax |
push eax |
mov al,[esi] |
call c8mono_2 |
push ax |
shl eax,16 |
pop ax |
mov ebx,eax |
pop eax |
jmp for_all_type_1 |
c8mono_2: |
sub al, 0x80 |
cbw |
imul ax, 255 |
ret |
c8stereo: |
mov [type_of_conversion],2 |
jmp for_all_type |
c8stereo_1: |
lodsb |
call c8stereo_2 |
shl eax,16 |
lodsb |
call c8stereo_2 |
push eax |
mov al,[esi] |
call c8stereo_2 |
shl eax,16 |
mov al,[esi+1] |
call c8stereo_2 |
mov ebx,eax |
pop eax |
jmp for_all_type_1 |
c8stereo_2: |
sub al, 0x80 |
cbw |
imul ax, 255 |
ret |
c16mono: |
mov [type_of_conversion],3 |
jmp for_all_type |
c16mono_1: |
lodsw |
push ax |
shl eax,16 |
pop ax |
mov bx,[esi] |
shl ebx,16 |
mov bx,[esi] |
jmp for_all_type_1 |
c16stereo: |
for_all_type: |
xor edx,edx |
mov eax, 15*1024*10 |
movzx ebx,[difference_of_frequency_2] |
xor edx,edx |
div ebx |
mov ecx,eax |
; mov ebx,10 |
; mov eax,edx |
; xor edx,edx |
; div ebx |
; cmp edx,5 |
; jb temp_12_6 |
; inc ecx |
; temp_12_6: |
cmp edx,0 |
je temp_12_6 |
inc ecx |
temp_12_6: |
c16stereo_1: |
mov [znak],0 |
cmp [type_of_conversion],1 |
je c8mono_1 |
cmp [type_of_conversion],2 |
je c8stereo_1 |
cmp [type_of_conversion],3 |
je c16mono_1 |
lodsd |
mov ebx,[esi] |
for_all_type_1: |
cmp eax,ebx |
jne c16stereo_2 |
inc [znak] |
c16stereo_2: |
push eax |
push ecx |
sub eax,ebx |
push eax |
shl eax,16 |
movzx ebx,[difference_of_frequency] |
inc ebx |
xor edx,edx |
div ebx |
shr eax,16 |
mov ecx,eax |
pop eax |
xor ax,ax |
xor edx,edx |
div ebx |
shl eax,16 |
mov cx,ax |
mov ebx,ecx |
pop ecx |
pop eax |
mov dl,[difference_of_frequency] |
inc dl |
@@: |
temp_12: |
cmp [difference_of_frequency_1],0 |
je temp_12_3 |
cmp [difference_of_frequency_1],5 |
jne temp_12_4 |
cmp [difference_of_frequency_4],2 |
jne temp_12_3 |
jmp temp_12_5 |
temp_12_4: |
cmp [difference_of_frequency_4],10 |
jne temp_12_3 |
temp_12_5: |
cmp [znak],0 |
jne temp_12_5_1 |
sub eax,ebx |
jmp temp_12_5_2 |
temp_12_5_1: |
add eax,ebx |
temp_12_5_2: |
stosd |
inc [schetchik] |
mov [difference_of_frequency_4],0 |
temp_12_3: |
cmp [znak],0 |
jne temp_13 |
sub eax,ebx |
jmp temp_14 |
temp_13: |
add eax,ebx |
temp_14: |
cld |
dec dl |
jz temp_14_1 |
stosd |
inc [schetchik] |
inc [difference_of_frequency_4] |
jmp temp_12 |
temp_14_1: |
dec ecx |
cmp ecx,0 |
; jnz c16stereo_1 |
jg c16stereo_1 |
newline |
dph [schetchik] |
temp_14_2: |
cmp [schetchik],15360 |
jge temp_14_3 |
stosd |
inc [schetchik] |
jmp temp_14_2 |
temp_14_3: |
newline |
dph [schetchik] |
cmp [schetchik],15360 |
je temp_14_4 |
; mov [edi-4],dword 0 |
sub edi,4 |
; sub esi,4 |
temp_14_4: |
mov [schetchik],0 |
ret |
difference_of_frequency db 0 |
difference_of_frequency_1 db 0 |
difference_of_frequency_2 db 0 |
difference_of_frequency_4 db 0 |
schetchik dd 0 |
znak db 0 |
type_of_conversion db 0 |
convert dd c8mono, c8stereo, c16mono, c16stereo |
blocks dd 30, 60, 60, 120 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; get_my_address - get base address of the program in physical memory |
;; in: nothing |
;; out: eax = address |
;start fix for MM (8) |
;function shouldn't used. |
;get_my_address: |
; pushad |
; mcall MF_PROCINFO, procinfo, PN_MYSELF |
; popad |
; mov eax, [procinfo.memory_start] |
;ret |
;end fix for MM (8) |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; set the last valid index to something other than we're currently playing |
;; so that we never end |
;; |
;; this routine just sets the last valid index to 1 less than the index |
;; that we're currently playing, thus keeping it in and endless loop |
;; input: none |
;; output: none |
updateLVI: |
push eax |
call getCurrentIndex |
; dps "index " |
; dpd eax |
; newline |
dec al |
and al, INDEX_MASK |
call setLastValidIndex |
pop eax |
ret |
;--------------------------------------------------------------------- |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; returns AL = current index value |
getCurrentIndex: |
push edx |
mov edx, PO_CIV_REG |
call NABMBAR_read_byte |
pop edx |
ret |
;--------------------------------------------------------------------- |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; input AL = index # to stop on |
setLastValidIndex: |
push edx |
mov edx, PO_LVI_REG |
call NABMBAR_write_byte |
pop edx |
ret |
;--------------------------------------------------------------------- |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; print_info - outputs debug information |
;; in: nothing |
;; out: nothing |
print_info: |
dps "BUS: " |
movzx eax, [bus] |
dph eax |
dps " DEVFN: " |
movzx eax, [devfn] |
dph eax |
dps " IRQ: " |
movzx eax, [AC97IRQ] |
dpd eax |
newline |
dps "CODEC_POWER_CTRL: " |
mov edx, CODEC_POWER_CTRL_REG |
call NAMBAR_read_word |
dph eax |
dps " (bits 0-3 should be set)" |
newline |
mov edx, 0x28 |
call NAMBAR_read_word |
dph eax |
dps " - supported features" |
newline |
mov edx, 0x2A |
call NAMBAR_read_word |
dph eax |
dps " - config" |
newline |
mov edx, 0x2C |
call NAMBAR_read_word |
dph eax |
dps " - PCM rate" |
newline |
ret |
;--------------------------------------------------------------------- |
;--- DATA OF PROGRAM ----------------------------------------------- |
;--------------------------------------------------------------------- |
volume dd 15 |
fileinfo: |
.mode dd 0 ; READ |
.first_block dd 0 |
.blocks dd 120 ; 120 Kb |
.dest dd LOAD_BUFFER ;file_data |
.work dd work_area |
; db "/HD/1/WINDOWS/MEDIA/WICEB7~1.WAV",0 |
;sz textbox_string, "/hd/1/testmuz/menuet11.wav",0 |
sz textbox_string, " ",0 |
; rb 256 |
;--------------------------------------------------------------------- |
IMAGE_END: ; end of program's image |
rb 100-textbox_string.size |
; textbox_string.size |
;--------------------------------------------------------------------- |
device_id dd ? ; (device_id << 16) + vendor_id |
lastbus db ? ; pci coordinates |
bus db ? |
devfn db ? |
AC97ICH4 db ? ; Intel ICH4 codec flag |
SI7012 db ? ; SiS SI7012 codec flag |
NAMBAR dw ? ; Audio Mixers Registers (base) |
NABMBAR dw ? ; Bus Master Registers (base) |
AC97IRQ db ? ; Interrupt request |
AC97INT db ? ; Interrupt pin |
wav_mode db ? ; bits per sample & channels |
;--------------------------------------------------------------------- |
ST_DONE = 0x0 ; for interacting with player's window |
ST_PLAY = 0x1 |
ST_EXIT = 0x2 |
ST_STOP = 0x4 |
status db ? |
;--------------------------------------------------------------------- |
phys_bdl_buffer rd 1 |
phys_wav_buffer1 rd 1 |
phys_wav_buffer2 rd 1 |
align 32 |
; Buffer Descriptors List |
; ___________________________ |
; | physical address | dword |
; |_________________________| |
; | attr | length | dword max. length = 65535 samples |
; |_________________________| |
BDL_BUFFER: |
rb 32*8 ; 32 descriptors, 8 bytes each |
;--------------------------------------------------------------------- |
file_data: |
WAV_BUFFER1: |
rb 60 * 1024 ; 60 Kb |
WAV_BUFFER2: |
rb 60 * 1024 |
LOAD_BUFFER: |
rb 60 * 1024 |
;--------------------------------------------------------------------- |
procinfo process_information |
work_area: |
rb 0x10000 |
;--------------------------------------------------------------------- |
rb 0x800 |
thread_stack: |
rb 0x1000 ; for stack |
STACK_P: |
MEMORY_END: |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
/programs/ac97wav/trunk/build_en.bat |
---|
0,0 → 1,4 |
@erase lang.inc |
@echo lang fix en >lang.inc |
@fasm ac97wav.asm ac97wav |
@pause |
/programs/ac97wav/trunk/build_ru.bat |
---|
0,0 → 1,4 |
@erase lang.inc |
@echo lang fix ru >lang.inc |
@fasm ac97wav.asm ac97wav |
@pause |
/programs/ac97wav/trunk/codec.inc |
---|
0,0 → 1,344 |
NAMBAR_read_byte: |
add dx, [NAMBAR] |
in al, dx |
ret |
NAMBAR_read_word: |
add dx, [NAMBAR] |
in ax, dx |
ret |
NAMBAR_read_dword: |
add dx, [NAMBAR] |
in eax, dx |
ret |
NAMBAR_write_byte: |
add dx, [NAMBAR] |
out dx, al |
ret |
NAMBAR_write_word: |
add dx, [NAMBAR] |
out dx, ax |
ret |
NAMBAR_write_dword: |
add dx, [NAMBAR] |
out dx, eax |
ret |
NABMBAR_read_byte: |
add dx, [NABMBAR] |
in al, dx |
ret |
NABMBAR_read_word: |
add dx, [NABMBAR] |
in ax, dx |
ret |
NABMBAR_read_dword: |
add dx, [NABMBAR] |
in eax, dx |
ret |
NABMBAR_write_byte: |
add dx, [NABMBAR] |
out dx, al |
ret |
NABMBAR_write_word: |
add dx, [NABMBAR] |
out dx, ax |
ret |
NABMBAR_write_dword: |
add dx, [NABMBAR] |
out dx, eax |
ret |
semaphore: |
push ecx edx |
mov edx, GLOB_STS_REG ; 0x30 global status register |
call NABMBAR_read_dword |
and eax, PRI_CODEC_RDY ; 100h primary codec ready |
jz .success ; exit if codec not ready !!! |
; mov ecx, 1024 ; try 1024 times |
mov ecx, 0ffffh ; try 65535 times |
.wait: |
mov edx, ACC_SEMA_REG ; 0x34 codec write semaphore |
call NABMBAR_read_byte |
and al, CODEC_BUSY ; 01h codec access semaphore |
jz .success ; exit if codec not busy !!! |
dec ecx |
jnz .wait |
pop edx ecx |
mov eax, 0 |
jmp .exit |
.success: |
pop edx ecx |
mov eax, 1 |
.exit: |
ret |
codecStop: |
push eax ebx edx |
mov edx, PO_CR_REG ; 0x1B control register |
mov al, 0 ; stop all PCM out data |
call NABMBAR_write_byte |
mcall MF_DELAY, eax ; ebx = (eax = MF_DELAY = 5); wait 50 ms |
mov edx, PO_CR_REG ; 0x1B control register |
mov al, RR ; reset PCM out regs |
call NABMBAR_write_byte |
mcall MF_DELAY, eax |
pop edx ebx eax |
ret |
; set voulme |
; in ax = volume level |
setVolume: |
push eax edx |
push eax |
call semaphore |
mov edx, CODEC_RESET_REG ; 0 |
xor eax, eax ; register reset the codec |
call NAMBAR_write_word |
call semaphore |
pop eax |
imul ax, 0101h ; set volume for both chn |
mov edx, CODEC_MASTER_VOL_REG ; 2 |
call NAMBAR_write_word |
push eax |
call semaphore |
pop eax ; set volume for both chn |
mov edx, CODEC_HP_VOL_REG ; 4 |
call NAMBAR_write_word |
push eax |
call semaphore |
mov edx, CODEC_CD_VOL_REG ; 12h |
pop eax ; set volume for both chn |
shr eax, 2 ; adjust CD VOL |
call NAMBAR_write_word |
call semaphore |
mov edx, CODEC_PCM_OUT_REG ; 18h |
mov ax, 0808h ; standard PCM out volume |
call NAMBAR_write_word |
pop edx eax |
ret |
samplerate dw 0 |
; enable codec, unmute stuff, set output to desired rate |
; in : ax = desired sample rate |
; out: ax = true or false |
; |
codecConfig: |
pushad |
mov [samplerate], ax ; save sample rate |
; mov edx, GLOB_STS_REG ; 30h global status register |
; call NABMBAR_read_dword |
; and eax, PRI_CODEC_RDY ; 0100h primary codec ready |
; jnz skip_init ; skip init if codec ready !!! |
; stop the codec if currently playing |
;;; call codecStop |
; mov edx, GLOB_STS_REG |
; call NABMBAR_read_dword |
; dps "GLOB_STA = " |
; dph eax |
; newline |
; mov edx, GLOB_CNT_REG |
; call NABMBAR_read_dword |
; dps "GLOB_CNT = " |
; dph eax |
; newline |
; mcall 5, 10 |
;; test eax, ACCOLD_RESET |
;; jnz .skip_cold_reset |
; print "cold reset" |
; do a cold reset |
mov edx, GLOB_CNT_REG ; 2ch global control register |
xor eax, eax |
call NABMBAR_write_dword ; enable (AC Link off clear) |
; print "wait" |
mcall 5, 5 |
; print "alive!" |
;; .skip_cold_reset: |
mov edx, GLOB_CNT_REG ; 2ch global control register |
mov eax, ACCOLD_RESET + PRI_RES_EN ; cold reset + primary resume |
call NABMBAR_write_dword ; 2 channels & 16 bit samples |
mov edx, GLOB_CNT_REG ; 2ch global control register |
call NABMBAR_read_dword |
and eax, ACCOLD_RESET ; cold reset |
jz init_error ; INIT FAILED !!! |
; print "cold reset finished" |
; wait for primary codec ready status |
mov ecx, 128 |
codec_ready_loop: |
mov edx, GLOB_STS_REG ; 30h global status register |
call NABMBAR_read_dword |
and eax, PRI_CODEC_RDY ; 0100h primary codec ready |
jnz codec_ready_exit ; move on if codec ready !!! |
mcall 5, 1 |
dec ecx |
jnz codec_ready_loop |
;dps "~" |
codec_ready_exit: |
; wait until codec init ready (*** replaces warm reset wait ***) |
mcall 5, 60 |
; test if codec ready bit is finally set |
mov edx, GLOB_STS_REG ; 30h global status register |
call NABMBAR_read_dword |
and eax, PRI_CODEC_RDY ; 0100h primary codec ready |
jnz codec_ready_bit_set ; move on if codec ready !!! |
cmp [AC97ICH4], 1 |
jne init_error |
; je codec_ready_bit_set ; ignore codec ready for ICH4 |
; jmp init_error ; codec ready bit not set !!! |
codec_ready_bit_set: |
; clear semaphore flag |
mov edx, CODEC_RESET_REG ; 0h codec reset register |
call NAMBAR_read_word |
; check if codec sections ready |
call semaphore |
test eax, eax |
jz init_error |
mov edx, CODEC_POWER_CTRL_REG ; 26h codec powerdown ctrl |
call NAMBAR_read_word |
and eax, 01111b |
cmp eax, 01111b |
jne init_error ; codec sections not ready |
; disable interrupts |
mov al, 0 |
mov edx, PI_CR_REG ; 0Bh PCM in control register |
call NABMBAR_write_byte |
mov edx, PO_CR_REG ; 1Bh PCM out control register |
call NABMBAR_write_byte |
mov edx, MC_CR_REG ; 2Bh MIC in control register |
call NABMBAR_write_byte |
; reset channels |
mov al, RR ; 02h reset Bus master regs |
mov edx, PI_CR_REG ; 0Bh PCM in control register |
call NABMBAR_write_byte |
mov edx, PO_CR_REG ; 1Bh PCM out control register |
call NABMBAR_write_byte |
mov edx, MC_CR_REG ; 2Bh MIC in control register |
call NABMBAR_write_byte |
; set default volume |
mov eax, 15 ; set average volume level |
call setVolume |
; set VRA and clear DRA (if not supported will be skipped) |
call semaphore |
test eax, eax |
jz init_error |
mov edx, CODEC_EXT_AUDIO_CTRL_REG ; register 2ah |
call NAMBAR_read_word ; get ext audio ctl |
mov ebx, eax |
call semaphore |
test eax, eax |
jz init_error |
mov eax, ebx |
and eax, 0FFFFh - BIT1 ; clear DRA (BIT1) |
or eax, BIT0 ; set VRA (BIT0) |
mov edx, CODEC_EXT_AUDIO_CTRL_REG ; register 2ah |
call NAMBAR_write_word ; write ext audio ctl |
; set desired sample rate |
skip_init: |
call semaphore |
test eax, eax |
jz init_error |
; mov edx, CODEC_PCM_FRONT_DACRATE_REG |
; call NAMBAR_read_word |
; and eax, 0xFFFF |
; newline |
; dps "old PCM OUT RATE: " |
; dpd eax |
; newline |
mov ax, [samplerate] ; restore sample rate |
; mov edx, CODEC_PCM_FRONT_DACRATE_REG ; register 2ch |
; call NAMBAR_write_word |
call set_sample_rate |
popad |
mov eax, 1 ; exit with success |
jmp exit_config |
init_error: |
popad |
xor eax, eax ; exit with error |
exit_config: |
ret |
set_sample_rate: ; rate in ax |
mov edx, CODEC_PCM_FRONT_DACRATE_REG ; 0x2C reg |
call NAMBAR_write_word |
ret |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
/programs/ac97wav/trunk/constant.inc |
---|
0,0 → 1,35 |
;constants of stuff that seem hard to remember at times. |
BIT0 EQU 1 |
BIT1 EQU 2 |
BIT2 EQU 4 |
BIT3 EQU 8 |
BIT4 EQU 10h |
BIT5 EQU 20h |
BIT6 EQU 40h |
BIT7 EQU 80h |
BIT8 EQU 100h |
BIT9 EQU 200h |
BIT10 EQU 400h |
BIT11 EQU 800h |
BIT12 EQU 1000h |
BIT13 EQU 2000h |
BIT14 EQU 4000h |
BIT15 EQU 8000h |
BIT16 EQU 10000h |
BIT17 EQU 20000h |
BIT18 EQU 40000h |
BIT19 EQU 80000h |
BIT20 EQU 100000h |
BIT21 EQU 200000h |
BIT22 EQU 400000h |
BIT23 EQU 800000h |
BIT24 EQU 1000000h |
BIT25 EQU 2000000h |
BIT26 EQU 4000000h |
BIT27 EQU 8000000h |
BIT28 EQU 10000000h |
BIT29 EQU 20000000h |
BIT30 EQU 40000000h |
BIT31 EQU 80000000h |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
/programs/ac97wav/trunk/debug.inc |
---|
0,0 → 1,131 |
macro debug_print str |
{ |
local ..string, ..label |
jmp ..label |
..string db str,0 |
..label: |
pushf |
pushad |
mov edx,..string |
call debug_outstr |
popad |
popf |
} |
dps fix debug_print |
macro debug_print_dec arg |
{ |
pushf |
pushad |
if ~arg eq eax |
mov eax,arg |
end if |
call debug_outdec |
popad |
popf |
} |
dpd fix debug_print_dec |
;--------------------------------- |
debug_outdec: ;(eax - num, edi-str) |
push 10 ;2 |
pop ecx ;1 |
push -'0' ;2 |
.l0: |
xor edx,edx ;2 |
div ecx ;2 |
push edx ;1 |
test eax,eax ;2 |
jnz .l0 ;2 |
.l1: |
pop eax ;1 |
add al,'0' ;2 |
call debug_outchar ; stosb |
jnz .l1 ;2 |
ret ;1 |
;--------------------------------- |
debug_outchar: ; al - char |
pushf |
pushad |
mov cl,al |
mov eax,63 |
mov ebx,1 |
int 0x40 |
popad |
popf |
ret |
debug_outstr: |
mov eax,63 |
mov ebx,1 |
@@: |
mov cl,[edx] |
test cl,cl |
jz @f |
int 40h |
inc edx |
jmp @b |
@@: |
ret |
macro newline |
{ |
dps <13,10> |
} |
macro print message |
{ |
dps message |
newline |
} |
macro pregs |
{ |
dps "EAX: " |
dpd eax |
dps " EBX: " |
dpd ebx |
newline |
dps "ECX: " |
dpd ecx |
dps " EDX: " |
dpd edx |
newline |
} |
macro debug_print_hex arg |
{ |
pushf |
pushad |
if ~arg eq eax |
mov eax, arg |
end if |
call debug_outhex |
popad |
popf |
} |
dph fix debug_print_hex |
debug_outhex: |
; eax - number |
mov edx, 8 |
.new_char: |
rol eax, 4 |
movzx ecx, al |
and cl, 0x0f |
mov cl, [__hexdigits + ecx] |
pushad |
mcall 63, 1 |
popad |
dec edx |
jnz .new_char |
ret |
__hexdigits: |
db '0123456789ABCDEF' |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
/programs/ac97wav/trunk/frontend.inc |
---|
0,0 → 1,270 |
thread: |
call draw_window |
call main_loop |
mov [status], ST_EXIT |
mcall MF_EXIT |
;--------------------------------------------------------------------- |
main_loop: |
cmp [status], ST_PLAY |
je @f |
mcall MF_WAIT_EVENT |
jmp .handle_event |
@@: |
call draw_progress_bar |
mcall MF_WAIT_EVENT_TIMEOUT, 80 |
.handle_event: |
cmp eax, EV_REDRAW |
je redraw |
cmp eax, EV_BUTTON |
je button |
cmp eax, EV_KEY |
je key |
jmp main_loop |
redraw: |
call draw_window |
jmp main_loop |
key: |
mcall MF_GETKEY |
cmp [textbox_active], 1 |
jne main_loop |
cmp ah, 13 |
je .enter |
cmp ah, 8 |
je .backspace |
movzx ecx, [textbox_position] |
cmp ecx, 47 |
jae .enter |
mov [textbox_string + ecx], ah |
inc [textbox_position] |
call textbox_draw |
jmp main_loop |
.enter: |
mov [textbox_active], 0 |
call textbox_draw |
jmp main_loop |
.backspace: |
movzx ecx, [textbox_position] |
test ecx, ecx |
jz main_loop |
mov [textbox_string + ecx], byte 0 |
dec [textbox_position] |
call textbox_draw |
jmp main_loop |
button: |
mcall MF_GETBUTTON |
cmp ah, 0x10 |
je play_button |
cmp ah, 0x11 |
je stop_button |
cmp ah, 0x12 |
je decr_button |
cmp ah, 0x13 |
je incr_button |
cmp ah, 0x14 |
je volm_button |
cmp ah, 0x15 |
je volp_button |
cmp ah, 0x20 |
je activate_textbox |
cmp ah, 0x30 |
je progressbar_click |
cmp ah, 1 |
jne main_loop |
; mov [status], ST_STOP |
; mcall MF_DELAY, 40 |
ret |
play_button: |
xor eax, eax |
xchg al, [textbox_active] |
cmp al, 0 |
je @f |
call textbox_draw |
@@: |
mov [status], ST_PLAY |
jmp main_loop |
stop_button: |
mov [status], ST_STOP |
jmp main_loop |
decr_button: |
; mov [status], ST_STOP |
; @@: |
; mcall 5, 1 |
; cmp [status], ST_DONE |
; jne @b |
; movzx esi, [textbox_position] |
; add esi, textbox_string |
; @@: |
; cmp byte [esi], '/' |
; je @f |
; dec esi |
; jmp @b |
; @@: |
; mov byte [esi+1], 0 |
; mov [fileinfo.first_block], 0 |
; mov [fileinfo.dest], WAV_BUFFER1 |
; mcall 58, fileinfo |
; add ebx, WAV_BUFFER1 |
; mov esi, WAV_BUFFER1+8 |
; .next_file: |
; cmp ebx, esi |
; jbe .fin |
; cmp word [esi], "WA" |
; jne .next_file |
; cmp byte [esi+1], "V" |
; jne .next_file |
; .fin: |
;mov eax, [fileinfo.first_block] |
;cmp eax, 1000 |
;jnl @f |
;mov [fileinfo.first_block], 0 |
;jmp main_loop |
;@@: |
;sub [fileinfo.first_block], 1000 |
;jmp main_loop |
incr_button: |
;add [fileinfo.first_block], 1000 |
jmp main_loop |
volm_button: |
inc byte [volume] |
and byte [volume], 0x1f |
jz volp_button |
or [volume], 0x10000000 |
jmp _print_volume |
; jmp main_loop |
volp_button: |
dec byte [volume] |
and byte [volume], 0x1f |
jz volm_button |
or [volume], 0x10000000 |
; jmp main_loop |
_print_volume: |
movzx eax, byte [volume] |
neg eax |
add eax, 31 |
dps "Volume: " |
dpd eax |
newline |
jmp main_loop |
activate_textbox: |
cmp [status], ST_DONE |
jne main_loop |
mov [textbox_active], 1 |
call textbox_draw |
jmp main_loop |
progressbar_click: |
;print "click on progress bar" |
cmp [status], ST_DONE |
je main_loop |
mcall MF_GETMOUSE, MS_COORDS_WINDOW |
shr eax, 16 ; get mouse.x |
sub eax, 7 |
test eax, eax |
jz @f |
imul eax, [file_size] |
mov ebx, 286 |
cdq |
div ebx |
@@: |
;dps "block: " |
;dpd eax |
;newline |
mov [fileinfo.first_block], eax |
call draw_progress_bar |
jmp main_loop |
ret |
;--------------------------------------------------------------------- |
PBAR_WIDTH = 286 |
draw_window: |
mcall MF_DRAWSTATUS, DS_BEGIN |
mcall MF_WINDOW, <100,299>, <100,72>, 0x03404040 |
; create six buttons |
mov edi, 6 |
mpack ebx, 7, 45 |
mpack ecx, 24, 13 |
mov edx, 0x10 |
mov esi, 0xA0A0A0 |
@@: |
mcall MF_BUTTON |
add ebx, 48 shl 16 |
inc edx |
dec edi |
jnz @b |
mcall MF_TEXT, <8,8>, 0x10FFFFFF, header, header.size |
mcall ,<13,28>, 0x404040, buttons_text, buttons_text.size |
sub ebx, 0x00010001 |
mov ecx, 0xFFFFFF |
mcall |
call draw_progress_bar |
call textbox_draw |
mcall MF_DRAWSTATUS, DS_END |
ret |
;--------------------------------------------------------------------- |
textbox_draw: |
mcall MF_BUTTON, <7,285>, <55,10>, 0x60000020 |
mov edx, 0x808080 |
cmp [textbox_active], 1 |
jne @f |
mov edx, 0xA0A0A0 |
@@: |
mcall MF_BAR, <7,286>, <55,11> |
movzx esi, [textbox_position] |
mcall MF_TEXT, <10,56>, 0x404040, textbox_string |
ret |
;--------------------------------------------------------------------- |
draw_progress_bar: |
pushad |
imul eax, [fileinfo.first_block], PBAR_WIDTH |
cdq |
div [file_size] |
push eax |
mcall MF_BAR, <7,286>, <41,11>, 0x808080 |
mcall MF_BUTTON, , , 0x60000030 |
pop eax |
mov bx, ax |
mov edx, 0xA0A0A0 |
mcall MF_BAR |
popad |
ret |
;--------------------------------------------------------------------- |
sz header, "AC'97 WAV player - all PCM audio" |
sz buttons_text, " Play Stop << >> Vol- Vol+" |
textbox_active db 0 |
textbox_position db textbox_string.size-1 |
file_size dd 100 |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
/programs/ac97wav/trunk/includes.inc |
---|
0,0 → 1,10 |
include "MACROS.INC" |
include "DEBUG.INC" |
include "CONSTANT.INC" |
include "AC97.INC" |
include "PCI.INC" |
include "CODEC.INC" |
include "FRONTEND.INC" |
MF_PCI = 62 |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
/programs/ac97wav/trunk/macros.inc |
---|
0,0 → 1,266 |
; new application structure |
macro meos_app_start |
{ |
use32 |
org 0x0 |
db 'MENUET01' |
dd 0x01 |
dd __start |
dd __end |
dd __memory |
dd __stack |
if used __params & ~defined __params |
dd __params |
else |
dd 0x0 |
end if |
dd 0x0 |
} |
MEOS_APP_START fix meos_app_start |
macro code |
{ |
__start: |
} |
CODE fix code |
macro data |
{ |
__data: |
} |
DATA fix data |
macro udata |
{ |
if used __params & ~defined __params |
__params: |
db 0 |
__end: |
rb 255 |
else |
__end: |
end if |
__udata: |
} |
UDATA fix udata |
macro meos_app_end |
{ |
align 32 |
rb 2048 |
__stack: |
__memory: |
} |
MEOS_APP_END fix meos_app_end |
; macro for defining multiline text data |
struc mstr [sstring] |
{ |
forward |
local ssize |
virtual at 0 |
db sstring |
ssize = $ |
end virtual |
dd ssize |
db sstring |
common |
dd -1 |
} |
; strings |
macro sz name,[data] { ; from MFAR [mike.dld] |
common |
if used name |
label name |
end if |
forward |
if used name |
db data |
end if |
common |
if used name |
.size = $-name |
end if |
} |
macro lsz name,[lng,data] { ; from MFAR [mike.dld] |
common |
if used name |
label name |
end if |
forward |
if (used name)&(lang eq lng) |
db data |
end if |
common |
if used name |
.size = $-name |
end if |
} |
; easy system call macro |
macro mpack dest, hsrc, lsrc |
{ |
if (hsrc eqtype 0) & (lsrc eqtype 0) |
mov dest, (hsrc) shl 16 + lsrc |
else |
if (hsrc eqtype 0) & (~lsrc eqtype 0) |
mov dest, (hsrc) shl 16 |
add dest, lsrc |
else |
mov dest, hsrc |
shl dest, 16 |
add dest, lsrc |
end if |
end if |
} |
macro __mov reg,a,b { ; mike.dld |
if (~a eq)&(~b eq) |
mpack reg,a,b |
else if (~a eq)&(b eq) |
mov reg,a |
end if |
} |
macro mcall a,b,c,d,e,f { ; mike.dld |
__mov eax,a |
__mov ebx,b |
__mov ecx,c |
__mov edx,d |
__mov esi,e |
__mov edi,f |
int 0x40 |
} |
; optimize the code for size |
__regs fix <eax,ebx,ecx,edx,esi,edi,ebp,esp> |
macro add arg1,arg2 |
{ |
if (arg2 eqtype 0) |
if (arg2) = 1 |
inc arg1 |
else |
add arg1,arg2 |
end if |
else |
add arg1,arg2 |
end if |
} |
macro sub arg1,arg2 |
{ |
if (arg2 eqtype 0) |
if (arg2) = 1 |
dec arg1 |
else |
sub arg1,arg2 |
end if |
else |
sub arg1,arg2 |
end if |
} |
macro mov arg1,arg2 |
{ |
if (arg1 in __regs) & (arg2 eqtype 0) |
if (arg2) = 0 |
xor arg1,arg1 |
else if (arg2) = 1 |
xor arg1,arg1 |
inc arg1 |
else if (arg2) = -1 |
or arg1,-1 |
else if (arg2) > -128 & (arg2) < 128 |
push arg2 |
pop arg1 |
else |
mov arg1,arg2 |
end if |
else |
mov arg1,arg2 |
end if |
} |
macro struct name |
{ |
virtual at 0 |
name name |
sizeof.#name = $ - name |
end virtual |
} |
; structures used in MeOS |
struc process_information |
{ |
.cpu_usage dd ? ; +0 |
.window_stack_position dw ? ; +4 |
.window_stack_value dw ? ; +6 |
.not_used1 dw ? ; +8 |
.process_name rb 12 ; +10 |
.memory_start dd ? ; +22 |
.used_memory dd ? ; +26 |
.PID dd ? ; +30 |
.x_start dd ? ; +34 |
.y_start dd ? ; +38 |
.x_size dd ? ; +42 |
.y_size dd ? ; +46 |
.slot_state dw ? ; +50 |
rb (1024-52) |
} |
struct process_information |
struc system_colors |
{ |
.frame dd ? |
.grab dd ? |
.grab_button dd ? |
.grab_button_text dd ? |
.grab_text dd ? |
.work dd ? |
.work_button dd ? |
.work_button_text dd ? |
.work_text dd ? |
.work_graph dd ? |
} |
struct system_colors |
; constants |
; events |
EV_IDLE = 0 |
EV_TIMER = 0 |
EV_REDRAW = 1 |
EV_KEY = 2 |
EV_BUTTON = 3 |
EV_EXIT = 4 |
EV_BACKGROUND = 5 |
EV_MOUSE = 6 |
EV_IPC = 7 |
EV_STACK = 8 |
; event mask bits for function 40 |
EVM_REDRAW = 1b |
EVM_KEY = 10b |
EVM_BUTTON = 100b |
EVM_EXIT = 1000b |
EVM_BACKGROUND = 10000b |
EVM_MOUSE = 100000b |
EVM_IPC = 1000000b |
EVM_STACK = 10000000b |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
/programs/ac97wav/trunk/meosfunc.inc |
---|
0,0 → 1,29 |
MF_WINDOW = 0 |
MF_GETKEY = 2 |
MF_TEXT = 4 |
MF_DELAY = 5 |
MF_BUTTON = 8 |
MF_PROCINFO = 9 |
PN_MYSELF = -1 |
MF_WAIT_EVENT = 10 |
MF_DRAWSTATUS = 12 |
DS_BEGIN = 1 |
DS_END = 2 |
MF_BAR = 13 |
MF_GETBUTTON = 17 |
MF_WAIT_EVENT_TIMEOUT = 23 |
MF_GETMOUSE = 37 |
MS_COORDS_WINDOW = 1 |
MF_PORTS = 46 |
PRT_RESERVE = 0 |
PRT_FREE = 1 |
MF_THREAD = 51 |
THR_CREATE = 1 |
MF_SYSTREE = 58 |
MF_PCI = 62 |
MF_EXIT = -1 |
MF_INTERNAL_SERVICES = 68 |
ALLOC_PHYS_MEM =5 |
FREE_PHYS_MEM =6 |
SET_PHYS_BUFFER =7 |
GET_PHYS_BUFFER =8 |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
/programs/ac97wav/trunk/pci.inc |
---|
0,0 → 1,46 |
PCI_CMD_REG = 04h ; reg 04, command reg |
IO_ENA = 0x00000001 ; i/o decode enable |
MEM_ENA = 0x00000002 ; memory decode enable |
BM_ENA = 0x00000004 ; bus master enable |
pciRegRead8: ; register in CL! |
mov bl, 4 |
mov bh, [bus] |
mov ch, [devfn] |
mcall MF_PCI |
ret |
pciRegRead16: |
mov bl, 5 |
mov bh, [bus] |
mov ch, [devfn] |
mcall MF_PCI |
ret |
pciRegRead32: |
mov bl, 6 |
mov bh, [bus] |
mov ch, [devfn] |
mcall MF_PCI |
ret |
pciRegWrite8: ; value in DL! |
mov bl, 8 |
mov bh, [bus] |
mov ch, [devfn] |
mcall MF_PCI |
ret |
pciRegWrite16: |
mov bl, 9 |
mov bh, [bus] |
mov ch, [devfn] |
mcall MF_PCI |
ret |
pciRegWrite32: |
mov bl, 10 |
mov bh, [bus] |
mov ch, [devfn] |
mcall MF_PCI |
ret |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |