前言
現在的電腦配備中 ,VGA已經是蠻普遍的顯示器 ,而電腦音效也從
以往的PC喇叭躍升為Adlib卡、聲霸卡 ,但是為什麼筆者會想介紹PC喇
叭呢 ,因為電腦裡面一定有喇叭 ,如果寫的程式不是電腦遊戲的話 ,
一般PC喇叭就夠用了 ,尤其是撰寫教學軟體(俗稱CAI)更是把PC喇叭視
為標準配備 ;到底PC喇叭能不能發出比擬音效卡的音樂呢 ,本文將為
您介紹一番。
PC喇叭撥放VOC檔:
.VOC檔是聲霸卡在錄音時 ,將音樂的類比訊號轉換成數位訊號 ,再
把這些數位化的資料儲存起來。問題是PC喇叭只能夠做ON/OFF的動作 ,
並不能夠做類比的變化 ,那麼應該要如何才能夠放音呢 ?
PC喇叭可以放出五線譜上音樂 ,其原理只是將喇叭做ON/OFF的動作
罷了 ,例如想產生高音的話 ,只需將喇叭的ON/OFF動作加快 ,就可以產
生較尖銳的聲音 ,同理如果要產生低音 ,只需放慢ON/OFF喇叭的速度 ;
在比較尖銳的音效裡 ,輸出的能量比較多 ,是不是我們可以加以利用 ?
DEBUG TEST.VOC
-D 100
2A82:0100 43 72 65 61 74 69 76 65-20 56 6F 69 63 65 20 46 Creative Voice F
2A82:0110 69 6C 65 1A 1A 00 0A 01-29 11 01 E5 06 00 83 01 ile.....)..e....
^^取樣值
2A82:0120 80 FF FB 28 7A 45 B2 CC-62 F8 37 3D 32 B9 07 91 ..{(zE2Lbx7=29..
2A82:0130 F4 C8 77 A4 F2 EE 70 78-99 71 F2 B6 11 8F AC 74 tHw$rnpx.qr6..,t
用DEBUG來看看VOC檔 ,不難發現檔頭有個"Creative Voice File"的
字眼 ,再看看取樣頻率 ,其計算方式 3E8h/(100h-取樣值83h)=取樣頻率
1000/(256-131)=8 ...... 代表此檔為8K取樣。
軟體規化:
OUT 43h,90h ;啟始喇叭
OUT 61h,13h ;
OUT 42h,00h ←─────┐ ;撥放VOC資料
OUT 42h,資料 ── loop ─┘ ;(迴圈)
OUT 43h,B6h ;
OUT 42h,33h ;關閉喇叭結束
OUT 42h,05h ;
OUT 61h,10h ;
用PC喇叭撥放VOC檔的程式列表(PLAYVOC.ASM):
code segment
assume cs:code
org 100h
start proc near
jmp next
mark1 db '┌─────────────────────┐',0ah,0dh
db '│Sound Blaster .VOC Player for PC Speacker.│',0ah,0dh
db '│ │',0ah,0dh
db '│ Written By Werong Ho│',0ah,0dh
db '└─────────────────────┘',0ah,0dh,'$'
vochead db 'Creative Voice File',00h
jp db 0ah,0dh,'$'
msg_1 db 'Digit-Data Filename : $'
msg_2 db 'Please Input Digitized Song Filename (SOUNDATA.DA)',0ah,0dh
db '-> $'
msg_3 db 'Please input Recording Frequency (6-22, default=$'
msg_4 db '):$'
msg_5 db 'Hit any key to start to play .',0ah,0dh,'$'
msg_6 db 'Playing... (ESC:Stop Space:Pause )',0ah,0dh,'$'
msg_7 db 'Can not open Digitized Song File.',0ah,0dh,'$'
msg_8 db 'file is not D/A Format !',0ah,0dh,'$'
msg_9 db '00$'
msg_10 db 'Memory not enough than 160K !',0ah,0dh,'$'
old_8 dw 0000h,0000h
old_1b dw 0000h,0000h
old_23 dw 0000h,0000h
old_24 dw 0000h,0000h
counter1 dw 0000h ;計時器 ,每發生幾次int8就
counter2 dw 0000h ;執行一次原來的int_8
clock dw 0000h ;修改int_8中斷速率
keyin db 20h,00h ;輸入VOC檔名
db 100h dup (0) ;
head1 dw 00h ;讀檔時的handel暫存區
keyclk db 03h,00h,00,00,00,00,00 ;輸入取樣頻率
defclock dw 0000h ;讀出的VOC檔取樣頻率
select db 00h ;選擇使用0-1那一區段
buffer1 dw 0000h ;64K區段
block1 dw 0000h ;區段資料數
write1 dw 0000h ;已用資料數
buffer2 dw 0000h ;64K區段
block2 dw 0000h ;區段資料數
write2 dw 0000h ;已用資料數
buffer3 db 100h dup (?) ;讀取VOC檔頭資料暫存區
stop db 00h ;暫停
break db 00h ;錯誤判定
no_data db 00h ;已無.VOC資料可讀
new_1b :
new_23 :
mov byte ptr cs:break,01h
iret
new_24 :
mov byte ptr cs:break,01h
mov al,00h
iret
new_8 :
push ax
push bx
push cx
push dx
push ds
push es
cmp byte ptr cs:stop,01h
jz L4
mov ax,cs
mov ds,ax
cmp byte ptr ds:select,00h
jnz L1
mov ax,ds:block1
mov bx,ds:write1
cmp ax,bx
jz L1
mov ax,ds:buffer1
mov es,ax
inc word ptr ds:write1
jmp L2
L1 :
mov byte ptr ds:select,01h
mov ax,ds:block2
mov bx,ds:write2
cmp ax,bx
jz L5
mov ax,ds:buffer2
mov es,ax
inc word ptr ds:write2
jmp L2
L5 :
mov byte ptr ds:select,00h
jmp L4
L2 :
mov al,00h
out 42h,al
mov al,es:[bx]
out 42h,al
L4 :
mov al,20h
out 20h,al
pop es
pop ds
pop dx
pop cx
pop bx
dec word ptr cs:counter1
jz L6
pop ax
iret
L6 :
mov ax,cs:counter2
mov cs:counter1,ax
pop ax
jmp dword ptr cs:old_8
;L3 :
mov byte ptr ds:stop,01h
jmp L5
mem_err :
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset msg_10
int 21h
mov ax,4cffh
int 21h
next :
mov sp,0ff00h
mov ah,4ah
mov bx,1000h
int 21h
jb mem_err
mov ah,48h
mov bx,1000h
int 21h
jb mem_err
mov cs:buffer1,ax
mov ah,48h
mov bx,1000h
int 21h
jb mem_err
mov cs:buffer2,ax
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset mark1
int 21h
cmp byte ptr es:[0080h],00h
jz L7
mov ah,09h
mov dx,offset msg_1
int 21h
mov si,offset keyin+2
mov di,0082h
L9 :
mov al,es:[di]
cmp al,0dh
jz L8
cmp al,00h
jz L8
mov ds:[si],al
inc di
inc si
jmp L9
L8 :
mov byte ptr ds:[si],'$'
mov ah,09h
mov dx,offset keyin+2
int 21h
mov byte ptr ds:[si],00h
mov ah,09h
mov dx,offset jp
int 21h
jmp L10
L7 :
mov ah,09h
mov dx,offset msg_2
int 21h
mov ah,0ah
mov dx,offset keyin
int 21h
mov bx,offset keyin+2
mov ah,00h
mov al,cs:keyin+1
add bx,ax
mov byte ptr cs:[bx],00h
mov ah,09h
mov dx,offset jp
int 21h
jmp L10
L10 :
mov ax,cs
mov ds,ax
mov ax,3d02h
mov dx,offset keyin+2
int 21h
jnb L11
mov ah,09h
mov dx,offset msg_7
int 21h
mov ax,4cffh
int 21h
L11 :
mov cs:head1,ax
mov ah,3fh
mov bx,cs:head1
mov cx,0020h
mov dx,offset buffer3
int 21h
mov ah,3eh
mov bx,cs:head1
int 21h
mov di,offset buffer3
mov si,offset vochead
L13 :
mov al,cs:[si]
cmp al,00h
jz L12
mov ah,cs:[di]
inc si
inc di
cmp ah,al
jz L13
mov ah,09h
mov dx,offset msg_8
int 21h
mov ax,4cffh
int 21h
L12 :
mov bx,offset buffer3+1eh
mov ax,cs:[bx]
not ax
mov ah,00h
mov bx,ax
mov ax,03e8h
xor dx,dx
div bx
mov cs:defclock,ax
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset msg_3
int 21h
mov ax,cs:defclock
mov si,offset msg_9+1
mov bx,000ah
L14 :
xor dx,dx
div bx
add dl,30h
mov cs:[si],dl
dec si
or ax,ax
jnz L14
mov ah,09h
mov dx,offset msg_9
int 21h
mov ah,09h
mov dx,offset msg_4
int 21h
mov ah,0ah
mov dx,offset keyclk
int 21h
cmp byte ptr cs:keyclk+1,00h
jz L15
mov si,offset keyclk+2
xor ax,ax
mov bx,000ah
L16 :
xor dx,dx
mul bx
mov dl,cs:[si]
inc si
sub dl,30h
cmp dl,0ah
jnb L17
add ax,dx
jmp L16
L17 :
xor dx,dx
div bx
mov cs:defclock,ax
jmp L15
L15 :
mov ax,cs:defclock
cmp ax,0006h
jb L23
cmp ax,0017h
jb L24
mov word ptr cs:defclock,0016h
jmp L24
L23 :
mov word ptr cs:defclock,0006h
jmp L24
L24 :
mov ax,04a6h
mov bx,cs:defclock
xor dx,dx
div bx
mov cs:clock,ax
mov bx,0037h
xor dx,dx
mul bx
mov cs:counter1,ax
mov cs:counter2,ax
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset jp
int 21h
mov ah,09h
mov dx,offset msg_5
int 21h
mov ah,07h
int 21h ;pause
mov ah,09h
mov dx,offset msg_6
int 21h
NOP ;error free
mov ax,3508h
int 21h
mov cs:old_8,bx
mov cs:old_8+2,es
mov ax,351bh
int 21h
mov cs:old_1b,bx
mov cs:old_1b+2,es
mov ax,3523h
int 21h
mov cs:old_23,bx
mov cs:old_23+2,es
mov ax,3524h
int 21h
mov cs:old_24,bx
mov cs:old_24+2,es
NOP
mov ax,cs
mov ds,ax
mov ax,251bh
mov dx,offset new_1b
int 21h
mov ax,2523h
mov dx,offset new_23
int 21h
mov ax,2524h
mov dx,offset new_24
int 21h
NOP
mov ax,3d02h
mov dx,offset keyin+2
int 21h
mov cs:head1,ax
mov ax,cs:buffer1
mov ds,ax
mov ah,3fh
mov bx,cs:head1
mov cx,0ffffh
mov dx,0000h
int 21h
mov cs:block1,ax
mov ax,cs:buffer2
mov ds,ax
mov ah,3fh
mov bx,cs:head1
mov cx,0ffffh
mov dx,0000h
int 21h
mov cs:block2,ax
mov ax,cs
mov ds,ax
cli
mov al,90h
out 43h,al
mov al,13h
out 61h,al
mov ax,cs
mov ds,ax
cli
mov ax,2508h
mov dx,offset new_8
int 21h
cli
mov al,34h
out 43h,al
mov ax,cs:clock
out 40h,al
xchg ah,al
out 40h,al
sti
L21 :
mov ax,cs:block1
mov bx,cs:write1
cmp ax,bx
jnz L26
mov ax,cs:block2
mov bx,cs:write2
cmp ax,bx
jnz L26
jmp L25
L26 :
cmp byte ptr cs:break,01h
jnz L30
jmp L25
L30 :
cmp byte ptr cs:no_data,00h
jnz L22
mov ax,cs:block1
mov bx,cs:write1
cmp ax,bx
jz L19
mov ax,cs:block2
mov bx,cs:write2
cmp ax,bx
jz L20
L22 :
mov ah,01h
int 16h
jz L21
mov ax,0000h
int 16h
cmp ax,3920h
jz L29
cmp ax,011bh
jnz L21
jmp L25
L29 :
xor byte ptr cs:stop,01h
jmp L21
L19 :
mov ax,cs:buffer1
mov ds,ax
mov ah,3fh
mov bx,cs:head1
mov cx,0fffeh
mov dx,0000h
int 21h
mov cs:block1,ax
mov word ptr cs:write1,0000h
jmp L27
L20 :
mov ax,cs:buffer2
mov ds,ax
mov ah,3fh
mov bx,cs:head1
mov cx,0fffeh
mov dx,0000h
int 21h
mov cs:block2,ax
mov word ptr cs:write2,0000h
jmp L27
L27 :
or ax,ax
jnz L28
mov byte ptr cs:no_data,01h
L28 :
jmp L21
L25 :
mov al,0ffh
out 40h,al
NOP
out 40h,al
xor ax,ax
mov es,ax
mov ax,cs:old_8
mov bx,cs:old_8+2
cli
mov es:[0020h],ax
mov es:[0022h],bx
sti
mov ax,cs:old_1b
mov bx,cs:old_1b+2
cli
mov es:[006ch],ax
mov es:[006eh],bx
sti
mov ax,cs:old_23
mov bx,cs:old_23+2
cli
mov es:[008ch],ax
mov es:[008eh],bx
sti
mov ax,cs:old_24
mov bx,cs:old_24+2
cli
mov es:[0090h],ax
mov es:[0092h],bx
sti
mov al,0b6h
out 43h,al
mov al,33h
out 42h,al
mov al,05h
out 42h,al
mov al,10h
out 61h,al
mov ax,4cffh
int 21h
start endp
code ends
end start
Q:放音以後有明顯的尖叫聲 ?
A:在高速的機器下這種現像才會改善 ,不然就只好將撥放速度加快 ,
若是自己撰寫程式的話 ,如果能避免使用INT_8 , 這種情形也有可
能改善 ,因為這樣主機執行速度也會增加。
Q:撥音時 ,偶會聽到雜音 ?
A:因為取樣[頻率設定為8的時後 ,表示每秒需8KBYTE記憶體 ,每撥
放64K以後 ,程式會讀取硬碟內的語音檔 ,此時會嚴重降低執行速度
,所以音調就變了 ,若要改善此現像 ,可改在RAM DISK下執行。
一位元數位錄放音機
或許您會發現聲霸卡錄音出來的資料檔實在是太大了 ,對於生產軟
軟體的公司而言 ,會增加磁片數量造成生產的成本 ,所以我們又想再試
其它方法可不可以減少資料檔的內容。
對了 ,既然喇叭發出聲音是靠ON/OFF的動作 ,如果我們改記錄這個
狀態而非音量高低 ,不就可以節省更多的空間 ,原先記錄的是八位元的
音量高低 ,現在只記錄一位元的喇叭狀態 ,這樣資料豈不可以縮小為原
先的八分之一 ,根據這個理論我們再做下一個實驗。
硬體電路:
IC LM339 (電壓比較器)
VR 100K (三隻腳)
GND
┌──┴───────┐
│ 12 │
├┐ │
├┘ │
│1 3 6 7│
└┬─┬────┬─┬┘
│ VCC │ └────┐
│ ↓ ☉註二
註一 ┌─VR──┬──-┘
VCC 100K GND
註一:接至印表埠第13號腳
註二:輸入音源(就是音樂喇叭的那兩條線)
註三:VCC電壓+5V ,調整VR可變電阻可調錄音品質
我們使用印表埠當做輸入訊號的傳輸埠 ,電路上的可變電阻可以用
來調整比較電壓高低 ,當電壓高過指定的位準 ,我們記錄為"1" ,低於指
定電壓則記錄為"0" ,最後將這些訊號記錄成檔案便完成了。
最後當您準備錄音時 ,請先執行TEST ,並調整可變電阻使其發音狀
況達到最好 ,才使用錄音程式 REC.EXE 來錄音。
數位音效測試程式(TEST.ASM):
code segment
assume cs:code,ds:code
org 100h
start proc near
jmp next
next :
mov cx,0100h
L3 :
loop L3
mov ah,01h
int 16h
jnz L2
mov dx,03bdh ;印表埠
in al,dx
test al,10h
jnz L1
mov al,30h ;喇叭OFF
out 61h,al ;
jmp next
L1 :
mov al,32h ;喇叭ON
out 61h,al ;
jmp next
L2 :
mov al,30h ;關閉喇叭並結束程式
out 61h,al
mov ax,0000h
int 16h
mov ax,4cffh
int 21h
start endp
code ends
end start
=========================================================================
一位元錄音機錄音程式(REC.ASM):
code segment
assume cs:code,ds:code
org 100h
start proc near
jmp next
old_8 dw 00,00
buffer1 dw 00
buffer2 dw 00
input db 10h,00,' '
head1 dw 00
playbyte dw 00
playbit db 01
error db 'Memory not enough than 128K !',0ah,0dh,'$'
msg_1 db 'Enter file name : $'
msg_2 db 'Press [Enter] Start ,any key About.',0ah,0dh,'$'
port dw 03bdh ;【輸入port】
clock1 dw 0227h
clock2 dw 0227h
new_8 :
push ax
push bx
push dx
push ds
mov ax,cs:buffer2
mov ds,ax
mov bx,cs:playbyte
mov ah,cs:playbit
mov dx,cs:port ;print port
in al,dx
test al,10h
pushf
mov al,ds:[bx]
popf
jnz L5
push ax
mov al,30h
out 61h,al
pop ax
clc
jmp L6
L5 :
push ax
mov al,32h
out 61h,al
pop ax
stc
jmp L6
L6 :
rcl al,01h
rol ah,01h
mov ds:[bx],al
cmp ah,01h
jnz L7
inc bx
cmp bx,0000h
jnz L7
L8 :
mov bx,cs:buffer2
add bx,1000h
mov cs:buffer2,bx
mov bx,0000h
L7 :
mov cs:playbyte,bx
mov ds:[bx],al
mov cs:playbit,ah
pop ds
pop dx
pop bx
dec word ptr cs:clock1
jz L9
mov ax,cs:clock2
mov ds:clock1,ax
mov al,20h
out 20h,al
pop ax
iret
L9 :
mov al,20h
out 20h,al
pop ax
iret
mem_err :
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset error
int 21h
mov ax,4cffh
int 21h
next :
mov ah,4ah
mov bx,0400h
int 21h
mov sp,03e00h
mov ah,48h
mov bx,0fffeh
int 21h
mov ah,48h
int 21h
jb mem_err
mov cs:buffer1,ax
mov cs:buffer2,ax
mov ax,3508h
int 21h
mov cs:old_8,bx
mov cs:old_8+2,es
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset msg_1
int 21h
mov ah,0ah
mov dx,offset input
int 21h
mov bx,offset input+2
mov ah,00h
mov al,cs:input+1
add bx,ax
mov byte ptr cs:[bx],00h
mov ah,3ch
xor cx,cx
mov dx,offset input+2
int 21h
jb mem_err
mov cs:head1,ax
nop
mov ax,cs
mov ds,ax
mov ax,2508h
mov dx,offset new_8
int 21h
cli
mov al,40h
out 36h,al
; mov ax,0077h ;10K Bit 取樣
mov ax,004ah ;16K Bit 取樣
out 40h,al
xchg ah,al
out 40h,al
sti
L3 :
mov ah,01h
int 16h
jz L3
mov ax,0000h
int 16h
cli
mov al,0ffh
out 40h,al
out 40h,al
sti
mov ax,cs:old_8+2
mov ds,ax
mov dx,cs:old_8
mov ax,2508h
int 21h
mov ax,cs:buffer1
mov ds,ax
nop
L4 :
mov ax,cs:buffer1
mov bx,cs:buffer2
cmp ax,bx
jz L2
mov ds,ax
mov ah,40h
mov bx,cs:head1
mov cx,8000h
mov dx,0000h
int 21h
mov ah,40h
mov bx,cs:head1
mov cx,8000h
mov dx,8000h
int 21h
mov ax,cs:buffer1
add ax,1000h
mov cs:buffer1,ax
jmp L4
L2 :
mov ax,cs:buffer1
mov ds,ax
mov ah,40h
mov bx,cs:head1
mov cx,cs:playbyte
mov dx,0000h
int 21h
mov ah,3eh
mov bx,cs:head1
int 21h
mov ax,4cffh
int 21h
start endp
code ends
end start
=============================================================================
一位元數位放音機(PLAY.ASM)
code segment
assume cs:code,ds:code
org 100h
start proc near
jmp next
mark1 db '┌────────────────────────┐',0ah,0dh
db '│ Digitized Sound Player PC Speaker Version 0.88 │',0ah,0dh
db '│ (C) Written By Werong Ho [8 Bit] │',0ah,0dh
db '└────────────────────────┘',0ah,0dh
db '$'
mark2 db 'Memory Space :$'
mark3 db 'Digit-Data Filename : $'
mark4 db 'Loading $'
mark5 db 'OK.',0ah,0dh,'$'
mark6 db ' Bytes ... $'
mark7 db 'Please input Recording Frequency (1-24, default=$'
mark8 db '):$'
mark9 db 'Hit any key to start to play .',0ah,0dh,'$'
mark10 db 0ah,0dh,'Playing... (ESC:Stop Space:Pause )',0ah,0dh,'$'
mark11 db 'Memory : $'
mark12 db 'Please Input Digitized Song Filename (SOUNDATA.DA)',0ah,0dh
db '-> $'
msg_1 db 'Can not open Digitized Song File.',0ah,0dh,'$'
msg_2 db 0ah,0dh,'Base Memory not enough !',0ah,0dh,'$'
msg_3 db 0ah,0dh,'Play Over !',0ah,0dh,'$'
msg_4 db 0ah,0dh,'Ctrl-Break !',0ah,0dh,'$'
msg_5 db 0ah,0dh,'file is not D/A Format !',0ah,0dh,'$'
msg_6 db 0ah,0dh,'Escape Key Press !',0ah,0dh,'$'
msg_7 db ' [Pause]$'
msg_8 db ' $'
jp db 0ah,0dh,'$'
sourceadds dw 00,00
startadds dw 00,00
endadds dw 00,00
playbit db 01h
clock dw 00
old_8 dw 00,00
old_1b dw 00,00
old_23 dw 00,00
break db 00
playover db 00
counter1 dw 00
counter2 dw 00
input db 0f0h,00h
file1 db 100h dup (?)
head1 dw 00
buffer1 db 100h dup (?)
pu_ds dw 00
pu_mem dw 00
pu_long dw 00,00
pu_khz db 00
stop db 00
show_play :
mov ax,cs
mov ds,ax
mov al,20h
call clear
mov ax,cs:sourceadds
mov bx,cs:sourceadds+2
mov cx,cs:startadds
mov dx,cs:startadds+2
sub cx,ax
jnb L26
sub dx,1000h
L26 :
sub dx,bx
test dx,0f00h
jz L29
add cx,8000h
L29 :
rol dx,01h
rol dx,01h
rol dx,01h
rol dx,01h
and dx,00ffh
mov ax,cx
mov bx,0400h
div bx
xor dx,dx
mov si,offset buffer1+3h
mov byte ptr cs:[si+1],'K'
mov byte ptr cs:[si+2],'$'
L28 :
xor dx,dx
mov bx,000ah
div bx
add dl,30h
mov cs:[si],dl
dec si
cmp ax,0000h
jnz L28
mov ah,09h
mov dx,offset buffer1
int 21h
mov dx,offset msg_8
cmp byte ptr cs:stop,00h
jz L32
mov dx,offset msg_7
L32 :
mov ah,09h
int 21h
ret
return :
mov al,0ffh
out 40h,al
out 40h,al
xor ax,ax
mov es,ax
mov ax,cs:old_8
mov bx,cs:old_8+2
cli
mov es:[0020h],ax
mov es:[0022h],bx
sti
mov ax,cs:old_1b+2
mov ds,ax
mov dx,cs:old_1b
mov ax,251bh
int 21h
mov ax,cs:old_23+2
mov ds,ax
mov dx,cs:old_23
mov ax,2523h
int 21h
mov ax,cs
mov ds,ax
mov es,ax
ret
khz :
push ax
push bx
push dx
mov bx,ax
mov ax,04a6h
xor dx,dx
div bx
mov cs:clock,ax
mov ax,bx
mov bx,0037h
xor dx,dx
mul bx
mov cs:counter1,ax
mov cs:counter2,ax
pop dx
pop bx
pop ax
ret
new_8 :
push ax
push bx
push cx
push dx
push ds
push es
mov ax,cs
mov ds,ax
cmp byte ptr ds:stop,01h
jnz L31
jmp L4
L31 :
mov ax,ds:startadds+2
mov es,ax
mov bx,ds:startadds
mov al,es:[bx]
mov ah,ds:playbit
rol ah,01h
rcl al,01h
jnb L1
mov es:[bx],al
mov al,32h
out 61h,al
jmp L2
L1 :
mov es:[bx],al
mov al,30h
out 61h,al
jmp L2
L2 :
mov ds:playbit,ah
cmp ah,01h
jnz L3
inc bx
mov ax,es
cmp bx,8000h
jnz L5
add ax,0800h
mov bx,0000h
L5 :
mov ds:startadds+2,ax
mov ds:startadds,bx
L3 :
mov ax,ds:startadds
mov bx,ds:startadds+2
mov cx,ds:endadds
mov dx,ds:endadds+2
cmp ax,cx
jnz L4
cmp bx,dx
jb L4
mov al,0ffh
out 40h,al
out 40h,al
mov byte ptr ds:playover,01h
xor ax,ax
mov es,ax
mov ax,ds:old_8
mov bx,ds:old_8+2
cli
mov es:[0020h],ax
mov es:[0022h],bx
sti
L4 :
pop es
pop ds
pop dx
pop cx
pop bx
dec word ptr cs:counter1
jz L6
mov al,20h
out 20h,al
pop ax
iret
L6 :
mov ax,cs:counter2
mov cs:counter1,ax
pop ax
jmp dword ptr cs:old_8
new_1b :
new_23 :
mov byte ptr cs:break,01h
iret
clear :
push bx
push cx
mov bx,offset buffer1
mov cx,00ffh
L7 :
mov cs:[bx],al
inc bx
loop L7
pop cx
pop bx
ret
next :
mov cs:pu_ds,ds
mov sp,03f00h
mov ah,4ah
mov bx,0800h
int 21h
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset mark1
int 21h
mov ah,09h
mov dx,offset mark2
int 21h
mov al,20h
call clear
mov ah,48h
mov bx,0fffeh
int 21h
mov cs:pu_mem,bx
push bx
mov ah,48h
int 21h
mov cs:sourceadds+2,ax
mov cs:startadds+2,ax
mov cs:endadds+2,ax
pop bx
mov byte ptr cs:buffer1+4,'K'
mov byte ptr cs:buffer1+5,'$'
mov si,offset buffer1+3
mov ax,bx
mov bx,0040h
xor dx,dx
div bx
L8 :
xor dx,dx
mov bx,000ah
div bx
add dl,30h
mov cs:[si],dl
dec si
cmp ax,0000h
jnz L8
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset buffer1
int 21h
mov ah,09h
mov dx,offset jp
int 21h
nop ;show memory space
mov ds,cs:pu_ds
mov al,ds:[80h]
cmp al,00h
jz L9
mov si,offset file1
mov di,0081h
L11 :
mov al,ds:[di]
cmp al,20h
jnz L10
inc di
loop L11
L10 :
mov al,ds:[di]
cmp al,0dh
jz L12
cmp al,00h
jz L12
mov cs:[si],al
inc di
inc si
jmp L10
L12 :
mov byte ptr cs:[si],00h
mov byte ptr cs:[si+1],'$'
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset mark3
int 21h
mov ah,09h
mov dx,offset file1
int 21h
mov ah,09h
mov dx,offset jp
int 21h
jmp L13
L9 :
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset mark12
int 21h
mov ah,0ah
mov dx,offset input
int 21h
mov bx,offset input+2
mov ah,00h
mov al,cs:input+1
add bx,ax
mov byte ptr cs:[bx],00h
mov byte ptr cs:[bx+1],'$'
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset jp
int 21h
jmp L13
L13 : ;input file name complete
mov ax,3508h
int 21h
mov cs:old_8,bx
mov cs:old_8+2,es
mov ax,351bh
int 21h
mov cs:old_1b,bx
mov cs:old_1b+2,es
mov ax,3523h
int 21h
mov cs:old_23,bx
mov cs:old_23+2,es
nop ;get_interupt
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset mark4
int 21h
mov ax,3d02h
mov dx,offset file1
int 21h
jnb L14
mov ah,09h
mov dx,offset jp
int 21h
mov ah,09h
mov dx,offset msg_1
int 21h
mov ax,4cffh
int 21h
L14 :
mov cs:head1,ax
mov ax,4202h
mov bx,cs:head1
xor cx,cx
xor dx,dx
int 21h
mov cs:pu_long,ax
mov cs:pu_long+2,dx
mov di,ax
mov si,dx
mov al,20h
call clear
mov bp,offset buffer1+6h
mov byte ptr cs:[bp+1],24h
L15 :
mov ax,si
mov bx,000ah
xor dx,dx
div bx
mov si,ax
mov ax,di
mov bx,000ah
div bx
mov di,ax
add dl,30h
mov cs:[bp],dl
dec bp
cmp si,0000h
jnz L15
cmp di,0000h
jnz L15
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset buffer1
int 21h
mov ah,09h
mov dx,offset mark6
int 21h
mov ax,4200h
mov bx,cs:head1
xor cx,cx
xor dx,dx
int 21h
mov ah,3fh
mov bx,cs:head1
mov cx,0002h
mov dx,offset buffer1
int 21h
mov al,cs:buffer1
cmp al,53h
jz L16
mov ah,3eh
mov bx,cs:head1
int 21h
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset msg_5
int 21h
mov ax,4cffh
int 21h
L16 :
mov al,cs:buffer1+1
mov cs:pu_khz,al
mov ah,00h
call khz
nop ;setup counter/clock
mov ax,cs:pu_long
mov bx,cs:pu_long+2
ror ax,01h
ror ax,01h
ror ax,01h
ror ax,01h
and ax,0fffh
ror bx,01h
ror bx,01h
ror bx,01h
ror bx,01h
and bx,0f000h
add ax,bx
inc ax
mov bx,cs:pu_mem
cmp ax,bx
jb L17
mov ah,3eh
mov bx,cs:head1
int 21h
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset msg_2
int 21h
mov ax,4cffh
int 21h ;check memory enough
L17 :
mov ax,cs:endadds+2
mov ds,ax
mov ah,3fh
mov bx,cs:head1
mov cx,8000h
mov dx,0000h
int 21h
cmp ax,8000h
jnz L18
mov ax,ds
add ax,800h
mov cs:endadds+2,ax
jmp L17
L18 :
mov cs:endadds,ax
mov ah,3eh
mov bx,cs:head1
int 21h
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset mark5
int 21h
nop ;loading complete
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset mark7
int 21h
mov si,offset buffer1+1
mov byte ptr cs:[si+1],24h
mov byte ptr cs:[si],20h
mov byte ptr cs:[si-1],20h
mov al,cs:pu_khz
mov ah,00h
L27 :
xor dx,dx
mov bx,000ah
div bx
add dl,30h
mov cs:[si],dl
dec si
cmp ax,0000h
jnz L27
mov ah,09h
mov dx,offset buffer1
int 21h
mov ah,09h
mov dx,offset mark8
int 21h
nop ;show default clock
mov byte ptr cs:file1,00h
mov ah,0ah
mov dx,offset input
int 21h
mov si,offset file1
xor ax,ax
L20 :
xor dx,dx
mov bx,000ah
mul bx
mov dl,cs:[si]
inc si
sub dl,30h
cmp dl,0ah
jnb L19
mov dh,00h
add ax,dx
jmp L20
L19 :
xor dx,dx
mov bx,000ah
div bx
cmp ax,0019h
jnb L21
cmp ax,0000h
jz L21
call khz
L21 :
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset jp
int 21h
mov ah,09h
mov dx,offset mark9
int 21h
mov ah,07h
int 21h
nop
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset mark10
int 21h
mov ah,09h
mov dx,offset mark11
int 21h
nop
mov ax,cs
mov ds,ax
mov ax,251bh
mov dx,offset new_1b
int 21h
mov ax,2523h
mov dx,offset new_23
int 21h
nop
mov ah,01h
mov cx,2020h
int 10h
mov ax,cs
mov ds,ax
mov ax,2508h
mov dx,offset new_8
int 21h
cli
mov al,40h
out 36h,al
mov ax,cs:clock
out 40h,al
xchg ah,al
out 40h,al
sti
nop
L22 :
mov ah,03h
mov bh,00h
int 10h
push dx
call show_play
pop dx
mov ah,02h
mov bh,00h
int 10h
cmp byte ptr cs:playover,01h
jz L23
cmp byte ptr cs:break,01h
jz L24
mov ah,01h
int 16h
jz L22
mov ax,0000h
int 16h
cmp ax,3920h
jnz L30
xor byte ptr cs:stop,01h
jmp L22
L30 :
cmp ax,011bh
jnz L22
call return
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset msg_6
int 21h
jmp L25
L23 :
call return
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset msg_3
int 21h
jmp L25
L24 :
call return
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset msg_4
int 21h
jmp L25
L25 :
mov ah,01h
mov cx,0d0eh
int 10h
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset jp
int 21h
mov ax,4cffh
int 21h
start endp
code ends
end start
[軟體使用說明]
REC.EXE 是錄音程式 ,程式第16行是使用的PORT
第135及136行是取樣頻率設定 ,前面加分號表示不使用 ,預設值
是使用16K Bit取樣。
鍵入後 ,再輸入檔名即開始錄音 ,錄音時會順便放音給您聽 ,本
程式啟動後 ,會讓電腦時間停止 ,以求得高速的錄音效果 ,並請
您使用較高速的機器錄音(筆者使用386 54MHz) ,以免當機。
錄音程式限用主記憶體 ,所以盡可能空出多一點記憶體供軟體使用 ,當
使用10K Bit取樣 ,每秒約用1.2K BYTE空間 ,若使用16K Bit取樣 ,每
秒需2K BYTE空間 ,若主記憶體不夠用 ,可能會當機。
TEST.EXE測試錄音效果 ,程式會把接收到的資料放出來 ,並不會錄起來 ,
此動作是為了讓使用者能調整錄音品質 ,及調整可變電阻至合適
的響應頻率 ,以得到較好的錄音品質。
PLAY.EXE是放音程式 ,請將完整的錄音資料檔檔頭用PCTOOLS修改一下 ,第
一個BYTE擺53h ,用以識別此檔是語音資料檔 ;第二個BYTE請修改
成您的錄音取樣頻率 ,例如您的取樣頻率是10K Bit ,請填入0Ah ,
若您是取樣16K Bit ,請填入 10h。
數位語音放因軟體 ,以Bit為單位做取樣 ,取樣頻率約為
16100.612 Bit/Sec ,也就是每秒要用掉約2K Bytes來放音。
(一般16K Bit取樣 ,錄音4分50秒左右約需580K記憶體)
結論:
我們在錄音、放音的實驗中 ,如果採VOC的錄音方式 ,即使再小聲
我們都可以錄的到 ,可是放音時如果主機速度不夠快 ,常會聽到尖銳的
聲音 ,其為模擬的音效無法確實還原 ;如果使用後者的錄音方式 ,可以
輕鬆的錄出蠻真實的音樂 ,雖比不上聲霸卡的真實 ,但表現的效果最好
,同時資料檔也是最小。