Помощь - Поиск - Пользователи - Календарь
Полная версия: Мелодия системного динамика
Форум «Всё о Паскале» > Delphi, Assembler и другие языки. > Assembler
КМА
Здравствуйте, уважаемые.

Есть задача:

Написать программу исполняющую на системном динамике песню про веселых гусей.

К сожалению, я пока не обладаю соответствующими навыками в программировании на ассемблере, но был бы очень признателен людям, которые откликнулись бы на эту тему и написали все что знаю о системном динамике, как к нему обращаться и работать. Как завершение этой темы, общими усилиями, хотелось бы написать процедуру биликанья динамика, т. е. в соответствии от введенной цифры он биликал бы соответствующую ноту. Вот.

Заранее благодарен тем, кто откликнется.
xds
Для начала - одна нота:
.8086
.model tiny
locals

; Темп (в ударах в минуту)
tempo   equ 120

; Таблица соответствия номеров полутонов обозначениям нот 
; (в буквенной нотации), S - диез
C   equ 0   ;"до"
D   equ 2   ;"ре"
E   equ 4   ;"ми"
F   equ 5   ;"фа"
G   equ 7   ;"соль"
A   equ 9   ;"ля"
B   equ 11  ;"си"
S   equ 1   ;#

;---------------------------------------------------------------
; play - воспроизведение ноты
;   note = номер полутона
;   octave = номер октавы
;   len = длительность для размера 4/4 и заданного темпа

play macro note,octave,len
    mov ax,octave shl 8 + note  ;начинаем играть ноту
    call play_note
    mov cx,4370/(tempo*len)     ;задержка
    call delay
    call stop_note              ;выключаем динамик
endm

.code
.startup
    ;воспроизведение ноты "ля" первой октавы
    play A,3,4

    ;выход
    mov ax,4C00h
    int 21h

;---------------------------------------------------------------
; play_note - начинает воспроизведение ноты
; вход:
;   al = номер полутона внутри октавы (0..11)
;   ah = номер октавы (3 = первая фортепианная)
; выход:
;   нет

play_note proc
    mov cl,ah       ;cl = номер октавы
    cbw             ;ax = номер полутона * 2
    shl ax,1
    lea bx,notes    ;bx = @notes[номер полутона]
    add bx,ax
    mov al,0B6h     ;загрузка упраляющего слова таймера
    out 43h,al      ;(меандер на 3-м канале)
    mov ax,[bx]     ;ax = notes[номер полутона] * 2^номер октавы
    shr ax,cl
    out 42h,al      ;загрузка коэффициента деления в 3-й канал таймера
    mov al,ah
    out 42h,al
    in al,61h       ;включение динамика
    or al,3
    out 61h,al
    ret
endp

;---------------------------------------------------------------
; stop_note - выключает динамик
; вход:
;   нет
; выход:
;   нет

stop_note proc
    in al,61h
    and al,not 1
    out 61h,al
    ret
endp

;---------------------------------------------------------------
; delay - задержка
; вход:
;   cx = длительность задержки в 1/18 с (точнее - в 65536/1193180 с)
; выход:
;   нет

delay proc
    xor ax,ax
    mov es,ax
@@1:
    mov ax,es:[46Ch]
@@2:
    hlt
    cmp ax,es:[46Ch]
    je @@2
    loop @@1
    ret
endp

.const

; notes - таблица коэффициентов деления для октавы 0 (контроктавы)
;   Коэффициенты деления для более высоких октав получаются 
;   путём умножения значений из таблицы на 2^(номер октавы)

notes:
    dw 36488    ;C
    dw 34445    ;C#
    dw 32511    ;D
    dw 30673    ;D#
    dw 28960    ;E
    dw 27328    ;F
    dw 25804    ;F#
    dw 24350    ;G
    dw 22981    ;G#
    dw 21694    ;A
    dw 20473    ;A#
    dw 19325    ;B

end


Добавлено через 12 мин.
http://podgoretsky.com/ftp/Docs/Asm/AsmBradly/8/8-2.html
http://www.cyberguru.ru/programming/assemb...mers-sound.html
КМА
Отлично, пойду разбираться с кодом, спасибо за наводку.
КМА
М
КМА, следи за тем, что печатаешь. Я исправил.. Лопарь



Я тута помучился чуть-чуть, и вообщем сделал такую прикольную вещь. По возможности оставил комментарии, мало ли кому понадобиться. Только она играет "Веселую овечку Мери".


TITLE mary        
;=================
;= сегмент стека =
;=================
mary_stack SEGMENT PARA STACK 'stack'
        db 64 dup('stack')
mary_stack ENDS   
;==================
;= сегмент данных =
;==================
mary_data SEGMENT PARA  PUBLIC 'data'
; время задержки  
mary_time dw 6 dup (25), 50
          dw 2 dup (25, 25), 50, 25, 25, 50
          dw 12 dup (25), 100
; цельная нота, это 100 (1 сек), половинная 50, 25 это четверть, и т. д.
;++++++++++++++++++++++
; мелодия мери    
mary_freq dw 330, 294, 262, 293, 3 dup(330)     ; 1-2 такт
          dw 3 dup(294), 330, 2 dup(392)        ; 3-4 такт
          dw 330, 294, 262, 294, 4 dup (330)    ; 5-6 такт
          dw 2 dup (294), 330, 294, 262, 0FFFFh ; 7-8 такт
; нота соответствуют частотам
; до 130,8        
; диез 138,6      
; ре 146,8        
; ми 164,8        
; диез 155,6      
; фа 174,8        
; соль 196        
; диез 185        
; ля 220          
; диез 207,7      
; си 246,9        
; ----------      
; до 261          
; диез 277,2      
; ре 293,7        
; диез 311,1      
; ми 329,6        
; фа 349,2        
; диез 370        
; соль 392        
; диез 415        
; ля 440          
; диез 464,2      
; cи 493,9        
mary_data ENDS    
;================ 
;= сегмент кода = 
;================ 
mary_code SEGMENT PARA PUBLIC 'code'
                  
mary proc far     
assume CS: mary_code, DS: mary_data, SS: mary_stack
        push DS   
        xor ax, ax   ; обнуляем ax
        push ax      ; DS:0000 по нему будем выходить в ОС
                  
        mov ax, mary_data ; явно определим сегмент данных
        mov DS, ax
        ; подготовим все для проигрыша звука, т. е.
        lea si, mary_freq   ; загрузим в si массив мелодии
        call play           ; запускаем процедуру play
       ret        
mary endp         
                  
; Процедра play проигрывает мелодию
; в регистре si должен находиться адрес массива мелодии
play proc near    
        push ax           ; cохраняем регистры
        push di   
        push si   
        push bp   
       @freq:     
         mov di, [si]     ; загружаем в di следующую ноту
         cmp di, 0FFFFh   ; сравниваем, не конец ли? (0FFFFh признак окончания)
         je @end_play     ; если конец, то заканчиваем проигрывать
                          ; если нет, то воспроизведем звук
         mov bx, mary_time+bp
         call sound       ; вызвав процедуру sound
         add si, 2        ; ставим указатель на следующую ноту
         add bp, 2        ; и соответственно на следующий такт
         jmp @freq        ; прыгаем на следующий проигрыш ноты
                  
       @end_play: 
         pop bp           ; восстанавливаем регистры
         pop si   
         pop di   
         pop ax   
      ret         
play endp         
                  
; процедура sound проигрывает звук
; в di соответствущая нота
; в bx задержка   
sound proc near   
        push ax       ; сохраним регистры
        push bx   
        push cs   
        push dx   
        push di   
                  
        mov al, 0BCh
        out 43h, al        ; запишем в al значение таймера
        mov dx, 14h        ; делитель времени
        mov ax, 4F33h      ; 1331000 делить на частоту
        div di    
        out 42h, al        ; младший байт счетчика таймера
        mov al, ah
        out 42h, al
        in al, 61h
        mov ah, al
        or al, 3           ; включаем динамики
        out 61h, al
        @waits:            ; делаем задержку
         mov cx, 10000     ; в 10 милисекунд
         loop $   
         dec bx            ; пока не кончиться bx
         jnz @waits        ; будем выводить звук
        mov al, ah
        out 61h, al        ; восстанавливаем порт в начальное состояник
                  
        pop di        ; восстановим регистры
        pop dx    
        pop cx    
        pop bx    
        pop ax    
       ret        
sound endp        
mary_code ENDS    
          END mary


Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.