381 lines
15 KiB
NASM
381 lines
15 KiB
NASM
;----------------------------------------------------------;
|
||
; Melody Generator (C)ChaN, 2005
|
||
|
||
|
||
.include "tn45def.inc" ;This is included in "Atmel AVR Studio"
|
||
.include "avr.inc"
|
||
.include "mg.inc"
|
||
|
||
.def _0 = r15
|
||
.def _Sreg = r14
|
||
.def _Zreg = r12
|
||
.def _Yreg = r10
|
||
.def _TmrH = r9
|
||
.def _TmrL = r8
|
||
.def _TmrS = r7
|
||
|
||
.equ N_NOTE = 6
|
||
|
||
|
||
;----------------------------------------------------------;
|
||
; Work Area
|
||
|
||
.dseg
|
||
.org RAMTOP
|
||
NoteIdx:.byte 1 ; Note rotation index
|
||
|
||
Notes: .byte (2+3+1+1+1+1)*N_NOTE
|
||
.equ ns_freq = 0 ;Angular Speed
|
||
.equ ns_rptr = 2 ;Wave table read pointer (16.8 fraction)
|
||
.equ ns_lvl = 5 ;Level
|
||
.equ ns_wrap = 6 ;Loop Flag
|
||
.equ ns_loop = 7 ;Loop Count
|
||
.equ ns_lp = 8 ;Level Pointer
|
||
.equ nsize = 9 ;size of this structure
|
||
|
||
|
||
;----------------------------------------------------------;
|
||
; Program Code
|
||
|
||
.cseg
|
||
; Interrupt Vectors (ATtiny45)
|
||
rjmp reset ; Reset
|
||
rjmp 0 ; INT0
|
||
rjmp 0 ; PCINT0
|
||
rjmp 0 ; TC1_COMA
|
||
rjmp 0 ; TC1_OVF
|
||
rjmp 0 ; TC0_OVF
|
||
rjmp 0 ; EE_RDY
|
||
rjmp 0 ; ANA_COMP
|
||
rjmp 0 ; ADC
|
||
rjmp 0 ; TC1_COMB
|
||
rjmp isr_tc0_coma ; TC0_COMA
|
||
; rjmp 0 ; TC0_COMB
|
||
; rjmp 0 ; WDT
|
||
; rjmp 0 ; USI_START
|
||
; rjmp 0 ; USI_OVF
|
||
|
||
|
||
;--------------------------------------------------------------------;
|
||
; Program Code
|
||
|
||
reset:
|
||
clr _0
|
||
ldiw X, RAMTOP ;Clear RAM
|
||
ldi AL, 0 ;AL = 0
|
||
st X+, _0 ; X address of RAM = _0
|
||
dec AL ; AL = AL-1
|
||
brne PC-2 ;循环256次?
|
||
|
||
; outi OSCCAL, 172 ;Adjust OSCCAL if needed.
|
||
|
||
outi PORTB, 0b001101 ;Initalize Port B
|
||
outi DDRB, 0b010010 ;/
|
||
|
||
outi PLLCSR, 0b00000110 ;Initialize TC1 in 250 kHz fast PWM mode.
|
||
outi TCCR1, 0b01100001 ;Connect TC1 to OC1A
|
||
outi GTCCR, 0b01100000 ;Connect TC1 to OC1B
|
||
|
||
outi OCR0A, 62 ;Initalize TC0 in 32 kHz interval timer.
|
||
outi TCCR0A, 0b00000010
|
||
outi TCCR0B, 0b00000010
|
||
outi TIMSK, (1<<OCIE0A)
|
||
|
||
|
||
start_play:
|
||
ldiw Z, score*2 ;score地址放到Z,*2是取低字节地址
|
||
cli ;清全局中断标志
|
||
clrw _Tmr ;清计数器
|
||
clr _TmrS ;清timers
|
||
sei ;开中断
|
||
|
||
pl_next:
|
||
lpmw B, Z+ ;//把Z的数放入B,然后z+1
|
||
rcall drv_decay ;//调用衰变包络生成函数,遍历每个通道,包络值放到ns_lvl寄存器
|
||
cli ;//关中断
|
||
cpw _Tmr, B ;//比较两个字,
|
||
sei ;开中断
|
||
brcs PC-5 ;如果C flag==1跳转到pl_next这里;<=B则继续循环
|
||
|
||
pl_note:
|
||
lpm CL, Z+ ;把Z地址的数放入CL,也就是乐谱
|
||
cpi CL, EoS ;EOS是乐谱结束标志
|
||
breq start_play ;结束就跳回start_play
|
||
mov AL, CL ;AL = CL
|
||
rcall note_on ;调用note_on函数
|
||
andi CL, en ;
|
||
breq pl_note ;if CL==0 jmp to pl_note
|
||
rjmp pl_next ;长跳转(+-2K words),CL部位0调到pl_next
|
||
|
||
|
||
|
||
;--------------------------------------------------------------------;
|
||
; Note ON
|
||
;
|
||
;Call: AL[6:0] = key number
|
||
;AL是传递过来的乐谱数据,也就是键值
|
||
|
||
note_on:
|
||
pushw Z
|
||
|
||
mov ZL, AL ;ZL = AL
|
||
lsl ZL ;左移一位
|
||
clr ZH ;ZH = 0
|
||
addiw Z, tbl_pitch*2 ;加载音高表地址
|
||
lpmw A, Z+ ;读取音高值到A
|
||
|
||
lds YL, NoteIdx ;读取NoteIdx音调循环索引到YL
|
||
addi YL, 9 ;YL+9
|
||
cpi YL, 9*N_NOTE ;比较YL和通道数的9倍
|
||
brcs PC+2 ;YL小于9*N_NOTE跳转到继续+9
|
||
clr YL ;清掉YL
|
||
sts NoteIdx, YL ;NoteIdx = YL
|
||
clr YH ;清掉YH
|
||
addiw Y, Notes ;YL+Notes
|
||
|
||
ldiw B, wt_attack*2 ;加载attach表地址到B寄存器
|
||
cli ;关中断
|
||
stdw Y+ns_freq, A ;把A也就是音高值放入ns_freq寄存器,两个字节
|
||
stdw Y+ns_rptr+1, B ;把B也就是attach值放入ns_rpter+1(波表读取指针)寄存器,两个字节
|
||
sei ;开中断
|
||
stdi Y+ns_lvl, 255 ;255放入ns_lvl寄存器
|
||
std Y+ns_wrap, AL ;AL放入ns_warp
|
||
std Y+ns_loop, _0 ;_0放入ns_loop
|
||
std Y+ns_lp, _0 ;_0放入ns_lp
|
||
|
||
popw Z
|
||
ret
|
||
|
||
|
||
;--------------------------------------------------------------------;
|
||
; Decay envelope generation 衰变包络生成器
|
||
; 1.判断该通道循环标志ns_wrap,如果等于255则不需要生成包络,跳到下一通道
|
||
; 2.判断循环次数ns_loop,如果循环次数小于12则不需要生成,跳到下一通道
|
||
; 3.判断层指针,如果层指针小于255,则生成完成,跳到下一通道;否则根据层指针加载包络表数据,并放入ns_lvl变量;
|
||
; 4.判断是否所有通道处理完,处理完则退出
|
||
; 该函数也就是遍历所有通道并判断是否需要加载包络表,需要的把包络表(对应层数)数据放到对应通道的ns_lvl变量里面。
|
||
; N1:对于Flash存储器的间址取数只能使用Z寄存器。由于程序存储器的地址是以字(双字节)为单位的,因此,16位地址指针寄存器Z的高15位为程序存储器的字地址,最低位LSB为“0”时,指字的低字节;为“1”时,指字的高字节。程序中使用伪指令db定义的七段码为一个字节,他保存在一个字的低字节处。如果定义字,应使用伪指令dw。
|
||
|
||
drv_decay:
|
||
pushw Z ;保存地址入栈
|
||
ldiw Y, Notes ;加载Notes地址
|
||
dd_lp:
|
||
ldd AL, Y+ns_wrap ;Has sustain loop not wrapped? 把循环标志数据放入AL
|
||
ldi AH, 255 ;把255放入AH
|
||
cp AL, AH ;比较AL和AH
|
||
breq dd_nxt ;/相等跳转,所以ns_wrap==255时该通道不需要生成包络
|
||
std Y+ns_wrap, AH ;Clear wrapped flag. AH的数保存到循环标志寄存器,这样下次就不需要再生成包络
|
||
ldd AL, Y+ns_loop ;循环数放到AL
|
||
inc AL ;循环次数加1
|
||
cpi AL, 12 ;循环次数是否到12,12大则C flag=1;
|
||
brcs PC+2 ;如果C flag==1跳转,也就是小于12次
|
||
ldi AL, 0 ;大于等于12次则AL清0
|
||
std Y+ns_loop, AL ;AL数放到ns_loop循环次数寄存器
|
||
brcs dd_nxt ;循环次数小于12跳转到下一通道
|
||
ldd ZL, Y+ns_lp ;层指针放到ZL
|
||
inc ZL ;层指针+1, 如果溢出ZL=0;则Z flag=1;
|
||
breq dd_nxt ;Z flag==1跳转,即层指针溢出则跳到下一通道
|
||
std Y+ns_lp, ZL ;不溢出则更新层指针寄存器
|
||
clr ZH ;ZH = 0
|
||
addiw Z, envelope*2 ;加载包络表地址到Z,因为包络表是16x16的单字节,存在于Z地址的低8位,所以*2。具体查看上面N1注释.
|
||
lpm AL, Z ;把Z地址的数据放入AL
|
||
std Y+ns_lvl, AL ;包络数据放入lvl层变量
|
||
dd_nxt: adiw YL, 9 ;切换到下一个通道的数组,9是每通道的结构体长度
|
||
cpi YL, low(Notes+nsize*N_NOTE) ;比较是否处理完所有通道
|
||
brne dd_lp ;不等跳转,也就是通道还没处理完
|
||
|
||
popw Z ;出栈Z
|
||
ret
|
||
|
||
|
||
|
||
;--------------------------------------------------------------------;
|
||
; 32 kHz wave form synthesising interrupt
|
||
|
||
|
||
isr_tc0_coma:
|
||
in _Sreg, SREG ;Save regs...
|
||
movw _Zreg, ZL ;
|
||
movw _Yreg, YL ;/
|
||
|
||
ldiw Y, Notes ;Process all notes
|
||
clrw T2 ;Clear accumlator
|
||
tone_lp:
|
||
ldd EH, Y+ns_rptr ;Load wave table pointer
|
||
lddw Z, Y+ns_rptr+1 ;/
|
||
lpm EL, Z ;Get a sample
|
||
lddw T4, Y+ns_freq ;Load angular speed
|
||
add EH, T4L ;Increase wave table ptr (next angle)
|
||
adc ZL, T4H ;
|
||
adc ZH, _0 ;/
|
||
cpi ZH, high(wt_end*2) ;Repeat sustain area
|
||
brcs PC+4 ;
|
||
subiw Z, (wt_end-wt_loop)*2 ;
|
||
std Y+ns_wrap, _0 ;/
|
||
std Y+ns_rptr, EH ;Save wave table ptr
|
||
stdw Y+ns_rptr+1, Z ;/
|
||
ldd EH, Y+ns_lvl ;Apply envelope curve
|
||
MULT ;/
|
||
addw T2, T0 ;Add the sample to accumlator
|
||
adiw YL, 9 ;Next note
|
||
cpi YL, low(Notes+nsize*N_NOTE);
|
||
brne tone_lp ;/
|
||
|
||
asrw T2 ;Divide it by 4
|
||
asrw T2 ;/
|
||
ldiw E, 253 ;Clip it between -255 to 253
|
||
cpw T2, E ;
|
||
brlt PC+2 ;
|
||
movw T2L, EL ;
|
||
ldiw E, -255 ;
|
||
cpw T2, E ;
|
||
brge PC+2 ;
|
||
movw T2L, EL ;/
|
||
asrw T2 ;Set it to PWM modulator
|
||
ror T2H ;
|
||
mov EL, T2L ;
|
||
subi EL, 0x80 ;
|
||
mov EH, EL ;
|
||
com EH ;
|
||
sbrc T2H, 7 ;
|
||
inc EL ;
|
||
out OCR1A, EL ;
|
||
out OCR1B, EH ;/
|
||
|
||
sec ;Increment sequense timer
|
||
adc _TmrS, _0 ;
|
||
adc _TmrL, _0 ;
|
||
adc _TmrH, _0 ;/
|
||
|
||
movw ZL, _Zreg ;Restore regs...
|
||
movw YL, _Yreg ;
|
||
out SREG, _Sreg ;/
|
||
|
||
reti
|
||
|
||
|
||
|
||
;--------------------------------------------------------------------;
|
||
; Score table
|
||
;--------------------------------------------------------------------;
|
||
|
||
score:
|
||
.include "melody.asm"
|
||
|
||
|
||
;--------------------------------------------------------------------;
|
||
; Pitch number to angular speed conversion table
|
||
;--------------------------------------------------------------------;
|
||
;Since sustain area of wave table, a cycle of fundamental frequency, is sampled
|
||
;in 128 points, the base frequency becomes 32000/128 = 250 Hz. The wave table
|
||
;lookup pointer, 16.8 fraction, is increased every sample by these 8.8 fractional
|
||
;angular speed values.
|
||
|
||
tbl_pitch: ; A B H C Cis D Dis E F Fis G Gis
|
||
.dw 225, 239, 253, 268, 284, 301, 319, 338, 358, 379, 401, 425 ; 220Hz..
|
||
.dw 451, 477, 506, 536, 568, 601, 637, 675, 715, 758, 803, 851 ; 440Hz..
|
||
.dw 901, 955, 1011, 1072, 1135, 1203, 1274, 1350, 1430, 1515, 1606, 1701 ; 880Hz..
|
||
.dw 1802, 1909, 2023, 2143, 2271, 2406, 2549, 2700, 2861, 3031, 3211, 3402 ; 1760Hz..
|
||
.dw 3604, 3818, 4046, 4286, 4542, 4812, 5098, 5400 ; 3520Hz
|
||
|
||
|
||
;--------------------------------------------------------------------;
|
||
; Envelope Table
|
||
;--------------------------------------------------------------------;
|
||
|
||
envelope:
|
||
.db 255,252,250,247,245,243,240,238,235,233,231,228,226,224,222,219
|
||
.db 217,215,213,211,209,207,205,203,201,199,197,195,193,191,189,187
|
||
.db 185,183,182,180,178,176,174,173,171,169,168,166,164,163,161,159
|
||
.db 158,156,155,153,152,150,149,147,146,144,143,141,140,139,137,136
|
||
.db 134,133,132,130,129,128,127,125,124,123,122,120,119,118,117,116
|
||
.db 115,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99
|
||
.db 98,97,96,95,94,93,92,91,90,89,88,87,87,86,85,84
|
||
.db 83,82,82,81,80,79,78,78,77,76,75,75,74,73,72,72
|
||
.db 71,70,69,69,68,67,67,66,65,65,64,64,63,62,62,61
|
||
.db 60,60,59,59,58,57,57,56,56,55,55,54,54,53,53,52
|
||
.db 51,51,50,50,49,49,48,48,48,47,47,46,46,45,45,44
|
||
.db 44,43,43,43,42,42,41,40,40,39,39,38,38,37,37,36
|
||
.db 35,35,34,34,33,33,32,31,31,30,30,29,29,28,28,27
|
||
.db 26,26,25,25,24,24,23,22,22,21,21,20,20,19,19,18
|
||
.db 17,17,16,16,15,15,14,13,13,12,12,11,11,10,10,9
|
||
.db 8,8,7,7,6,6,5,4,4,3,3,2,2,1,1,0
|
||
|
||
|
||
;--------------------------------------------------------------------;
|
||
; Wave Table
|
||
;--------------------------------------------------------------------;
|
||
; 8bit, 32 ksps, 250 Hz fundamental frequency
|
||
|
||
.org 3072/2 ; Bottom stored
|
||
|
||
wt_attack: ; Attack area
|
||
.db 0, 0, 0, 0, 0, 0, -1, -2, -2, -3, -2, -2, -1, 0, 0, 0
|
||
.db 0, 0, -1, -2, -3, -3, -4, -4, -3, -2, -1, 0, 0, 1, 0, 0
|
||
.db 0, -1, -2, -3, -3, -2, 0, 0, 2, 4, 5, 5, 5, 3, 1, 0
|
||
.db -2, -3, -4, -3, -2, 0, 1, 2, 3, 2, 0, -2, -6, -11, -15, -18
|
||
.db -19, -19, -16, -11, -5, 1, 8, 15, 20, 23, 24, 23, 20, 17, 13, 10
|
||
.db 7, 6, 6, 8, 10, 13, 16, 18, 20, 20, 20, 19, 18, 18, 18, 18
|
||
.db 19, 21, 24, 26, 27, 28, 27, 25, 22, 17, 11, 5, 0, -5, -9, -12
|
||
.db -13, -13, -11, -9, -5, -1, 1, 4, 6, 6, 4, 0, -5, -12, -21, -30
|
||
.db -39, -48, -56, -62, -66, -69, -70, -71, -70, -70, -70, -71, -72, -75, -77, -79
|
||
.db -80, -78, -75, -69, -61, -50, -38, -26, -13, -2, 7, 15, 21, 25, 28, 30
|
||
.db 33, 36, 40, 44, 49, 55, 59, 61, 62, 60, 56, 49, 42, 34, 27, 22
|
||
.db 20, 21, 25, 33, 42, 52, 63, 72, 80, 86, 89, 90, 89, 87, 84, 81
|
||
.db 79, 77, 75, 73, 72, 69, 66, 61, 55, 48, 39, 31, 22, 14, 6, 0
|
||
.db -5, -10, -14, -17, -20, -22, -24, -26, -28, -29, -30, -31, -32, -33, -34, -35
|
||
.db -36, -37, -39, -41, -44, -48, -52, -57, -63, -70, -77, -85, -94, -102, -110, -116
|
||
.db -121, -124, -124, -121, -116, -109, -99, -89, -78, -68, -60, -53, -48, -45, -43, -43
|
||
.db -43, -42, -41, -40, -37, -33, -29, -25, -22, -19, -17, -16, -15, -14, -12, -9
|
||
.db -4, 2, 11, 22, 34, 46, 57, 67, 75, 81, 84, 86, 87, 86, 86, 85
|
||
.db 85, 85, 86, 86, 87, 86, 84, 82, 78, 73, 69, 64, 60, 58, 56, 57
|
||
.db 59, 62, 66, 70, 75, 79, 83, 86, 89, 91, 92, 92, 92, 90, 86, 81
|
||
.db 73, 63, 52, 38, 24, 9, -5, -19, -31, -42, -50, -57, -61, -64, -66, -67
|
||
.db -68, -68, -68, -67, -66, -64, -61, -56, -52, -46, -41, -36, -32, -29, -28, -28
|
||
.db -30, -34, -39, -44, -50, -56, -62, -68, -74, -79, -84, -90, -95, -100, -104, -107
|
||
.db -108, -108, -107, -103, -98, -92, -84, -76, -67, -58, -49, -40, -32, -24, -16, -8
|
||
.db -1, 5, 11, 16, 20, 22, 22, 21, 18, 14, 10, 5, 1, -1, -3, -3
|
||
.db -2, 0, 1, 5, 9, 12, 16, 20, 24, 28, 34, 40, 47, 55, 64, 72
|
||
.db 81, 89, 96, 101, 105, 108, 108, 108, 107, 105, 103, 101, 100, 98, 96, 93
|
||
.db 90, 87, 83, 79, 75, 70, 66, 62, 59, 56, 55, 53, 52, 51, 50, 48
|
||
.db 46, 44, 42, 39, 37, 34, 31, 28, 24, 20, 15, 10, 3, -3, -12, -21
|
||
.db -30, -39, -48, -57, -65, -72, -79, -85, -90, -95, -99, -103, -106, -109, -110, -112
|
||
.db -112, -112, -111, -110, -109, -107, -106, -105, -104, -104, -103, -102, -101, -99, -97, -94
|
||
.db -90, -86, -82, -78, -75, -72, -69, -67, -65, -63, -61, -58, -54, -50, -44, -38
|
||
.db -31, -23, -16, -10, -4, 1, 6, 10, 14, 18, 23, 27, 32, 38, 43, 49
|
||
.db 54, 59, 63, 67, 70, 73, 75, 77, 79, 81, 83, 85, 88, 91, 93, 96
|
||
.db 99, 101, 103, 105, 107, 109, 110, 111, 112, 112, 112, 111, 109, 107, 104, 100
|
||
.db 96, 92, 88, 83, 79, 75, 70, 65, 60, 55, 49, 43, 36, 30, 24, 18
|
||
.db 12, 7, 3, 0, -3, -6, -8, -11, -14, -17, -20, -24, -28, -32, -37, -42
|
||
.db -46, -51, -55, -59, -63, -67, -71, -75, -79, -82, -85, -88, -91, -93, -95, -97
|
||
.db -98, -100, -101, -102, -103, -104, -104, -104, -103, -101, -99, -96, -93, -89, -86, -83
|
||
.db -80, -78, -76, -75, -74, -73, -72, -71, -70, -68, -65, -63, -59, -56, -52, -48
|
||
.db -44, -40, -35, -30, -24, -18, -11, -4, 3, 11, 19, 27, 34, 41, 48, 53
|
||
.db 58, 63, 67, 71, 75, 79, 82, 86, 89, 92, 94, 95, 96, 97, 98, 98
|
||
.db 99, 100, 101, 103, 105, 108, 110, 112, 114, 115, 115, 114, 113, 110, 107, 103
|
||
.db 99, 95, 91, 87, 83, 79, 74, 70, 65, 59, 53, 47, 41, 35, 29, 24
|
||
.db 19, 14, 11, 7, 4, 1, -1, -5, -9, -14, -19, -25, -31, -37, -43, -50
|
||
.db -56, -62, -68, -73, -78, -83, -88, -92, -97, -101, -105, -109, -112, -115, -117, -119
|
||
.db -120, -121, -120, -119, -118, -116, -114, -112, -109, -106, -104, -101, -99, -96, -94, -91
|
||
.db -88, -85, -81, -78, -74, -70, -66, -62, -57, -53, -49, -45, -41, -37, -32, -27
|
||
.db -22, -16, -10, -4, 1, 8, 14, 20, 25, 31, 36, 41, 46, 50, 55, 60
|
||
.db 64, 69, 73, 77, 81, 85, 88, 90, 93, 95, 97, 99, 101, 103, 106, 109
|
||
.db 112, 115, 118, 121, 123, 125, 126, 126, 125, 125, 123, 121, 119, 117, 115, 112
|
||
.db 110, 107, 103, 99, 94, 89, 83, 76, 69, 62, 54, 47, 39, 31, 24, 16
|
||
.db 9, 2, -4, -11, -18, -25, -31, -38, -44, -51, -57, -62, -68, -73, -79, -84
|
||
.db -88, -93, -97, -102, -106, -109, -113, -116, -119, -121, -123, -124, -125, -126, -127, -127
|
||
.db -127, -127, -126, -125, -125, -123, -122, -120, -118, -116, -114, -111, -107, -104, -100, -95
|
||
.db -91, -86, -80, -75, -69, -63, -58, -52, -46, -40, -34, -28, -22, -16, -10, -4
|
||
|
||
wt_loop: ; Sustain area
|
||
.db 0, 5, 11, 17, 23, 28, 34, 39, 45, 50, 55, 60, 65, 69, 74, 78
|
||
.db 82, 85, 89, 92, 95, 98, 100, 102, 104, 106, 107, 109, 109, 110, 110, 111
|
||
.db 110, 110, 109, 108, 107, 106, 104, 102, 100, 98, 95, 93, 90, 87, 83, 80
|
||
.db 76, 72, 68, 64, 59, 55, 50, 46, 41, 36, 31, 26, 21, 15, 10, 5
|
||
.db 0, -5, -10, -15, -21, -26, -31, -36, -41, -46, -50, -55, -59, -64, -68, -72
|
||
.db -76, -80, -83, -87, -90, -93, -95, -98, -100, -102, -104, -106, -107, -108, -109, -110
|
||
.db -110, -111, -110, -110, -109, -109, -107, -106, -104, -102, -100, -98, -95, -92, -89, -85
|
||
.db -82, -78, -74, -69, -65, -60, -55, -50, -45, -39, -34, -28, -23, -17, -11, -5
|
||
wt_end:
|
||
|