Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Asm для Windows/Dos > Music in DOS


Автор: xach 4.7.2005, 03:57
Привет Друзья!

Как на счёт звука (пусть даже самого простейшего) на АСМе.
Можно ссылочку, но пожалуйста на русском, а то английский слишком
утомительным получается. Я имею ввиду чистый код, без всяких DLL и модулей.

smile

Автор: Akina 4.7.2005, 10:24
В ДОсе?

Код

Beep Proc
mov ah,2
mov dl,7
int 21h
ret
Beep endp


Проще уж просто некуда...

Автор: xach 5.7.2005, 01:44
Я имею ввиду хотя б простую мелодию выдать.
Не обязательно из Спикера...

Автор: oleg1973 5.7.2005, 10:50
xach
если не на спикер то значит на звуковуху
если на звуковуху то нада знать модель, так как в досе HAL нету и подход персональный к каждой карте
кстати в инете куча сорцов о програмировании SB16-32
НО современные SB1024 и позже нихренам не совместимы, сам проверял, и прямому програмирования из доса не поддаются за неимением документации

Автор: xach 6.7.2005, 01:03
Раз всё так ужасно... Как на счёт спикера тогда уж... Возможно ли
извлечь из него мелодию, которая бы не раздражала уши? smile
Тогда уж подскажите про спикер (там уж всё просто должно быть (я так думаю))!
Именно мелодию, а не beep.

Автор: monax 14.7.2005, 21:03
Раньше никогда этим не занимался, но стало интересно и вот...
Программа играет (точнее имитирует)
"-Чижик Пыжик, где ты был?
-На Фонтанке водку пил"
Информация о динамике взята http://podgoretsky.com/ftp/Docs/Asm/AsmBradly/8/8-2.html
Код

code segment
assume cs:code, ds:code, es:code
org 100h
start:

; -----сохранение старого вектора прерывания от таймера-----
mov ah,35h  
mov al,8h
int 21h
mov old_08_seg,es
mov old_08_off,bx
;-----замена прерывания от таймера------
lea dx,IsrTimer
mov ah,25h
mov al,8h
int 21h

mov ah,9h
lea dx,mymsg
int 21h
xor ah,ah ;ждём нажатия клавиши, пока не нажата, играет музыка
int 16h

;------восстанавливаю вектор прерывания от таймера------
mov ah,25h
mov al,8h
mov ds,old_08_seg
mov dx,old_08_off
int 21h

;-----выключение динамика------
in al,61h
and al,11111100b
out 61h,al

mov ax,4c00h ;выход в ДОС
int 21h


IsrTimer proc far ;обработчик прерывания от таймера
push ax
push si
push ds
push dx

    push cs
    pop ds    

    inc m    
    cmp index,30
    jl TimerMet1
    mov index,0 ;обнуление счётчика
TimerMet1:    
    lea si,delay
    add si,index
    mov cx,[si]    
    cmp m,cx
    jl TimerMet2
pop ds    
    mov al,10110110b
    out 43h,al

    in al,61h
    or al,00000011b
    out 61h,al
push ds
push cs
pop ds
    xor dx,dx    
    lea si,chast
    add si,index
    mov ax,[si]
    mov tone,ax    
    mov ax,11900
    div tone
    mul tt

    out 42h,al
    mov al,ah
    out 42h,al
    mov m,0    
    add index,2
TimerMet2:    
    
    ;inc m            
    mov al,20h ;разрешить другие прерывания

pop dx
pop ds
pop si
pop ax

iret
IsrTimer endp
;----------------------данные-------------------

mymsg db 'Press any key$'
old_08_seg dw 0
old_08_off dw 0
index dw 0
m dw 0
tt db 100
tone dw 0

delay dw 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 2, 2, 4, 4, 8
chast dw 392, 311, 392, 311, 415, 392, 349, 233, 233, 233, 261, 293, 311, 311, 311;частоты
code ends
end start


Вот как это выглядит на С++
Код

#include<dos.h>
#include<conio.h>

int chast[15]={392,311,392,311,415,392,349, 233,233,233,261,293,311,311,311};
int dlit[15]={200,200,200,200,200,200,400,200,200,200,100,100,200,200,400};//задержки в милисекундах
void main()
{
int i;
i=0;
while(!kbhit())
    {
    if(i>=15) i=0;
    sound(chast[i]);
    delay(dlit[i]);
    i++;
    }
nosound();
}


Вся идея довольно проста: зная частоту ноты и её длительность в мелодии, можно сделать некое подобие музыки.
Ассемблерный код компилировал 5-м тасмом, с++ - BC 3.1.

Автор: Mayk 14.7.2005, 21:10
В игре Doom2D использовался спикер для воспроизведения голосовых сообщений. Качество, как у плохого телефона, но всё же. Как они это делают?

Автор: oleg1973 15.7.2005, 15:53
ну так никто не запрешает через спикер прогнать wav
толко нада сначала сделать его как бы однобитным имхо
тоесть там в порту спикера за звук если не путаю 1 бит только отвечает

Автор: xach 16.7.2005, 00:19
Со спикером я воспринял)... т.е. ещё не попробовал, но обязательно сдеалаю это
Вот увидел програмку в 111 байт с 0a000h (это party). Там звук выдаётся (по заверению
автора) через 220h порт... Хотя при дизассемблировании я увидел передачу в 226h и в 22ch
порты...(если ошибся извините))) Просто скопировал часть кода в Фасм, а звука нет
(уверен, что скопировал не то(или не всё) => не пишите, что я не то скопировал)))
Лучше помогите разобраться с кодом)))..
(под XP не работает(может можно через эмулятор какой-нибудь))

Автор: chyapay 18.8.2006, 17:24
Чувак, я так понял, ты наше какую-то дребедень про СаундБластер. Я тоже когда-то этим страдал. 
это старый хороший стандарт звуковых плат с портами 220h(227h, 22Fh) для восьмибитных и шестнадцатибитных 
Само собой, эта штука на новых звуковых проконает разве что из-под винды, которая спецыально эмулирует 
для досовских приложений этот интерфейс. Но и это - при большом везении. И я уверен, что ты правильно скопировал
эту хрень, но, к сожалению, играть она будет разве что на старом 386 динозавре с ИСАшной звуковой. 
В данном случае я могу порекоммендовать только одно : ищи в интернете документацию под свою звуковуху,
они обычно в формате ПДФ, типа AC97AudioController-specs.pdf, линков пока никаких дать не могу: сам этим делом страдаю, пока еще нифига не нашел. 

Автор: 10110111 29.8.2006, 13:51
Спецификация на AC97 - не проблема:
http://www.intel.com/design/chipsets/audio/ac97r22.pdf
В DDK есть даже пример WDM-драйвера.
Проблема вот в чем: когда я под DOS пытаюсь читать из пространства I/O Mixer'а, проц зависает; но на этом же компе Windows ME без проблем воспроизводит звук. Я уже думал, может, под DOS AC97 выключен, но отключение APM не дало никакого результата.
Может, кто-нибудь знает, почему такое может быть?

Автор: 10110111 30.10.2006, 21:38
Я написал прогу, выводящую WAVы через спикер: по знаку выборки из WAV'а
Вызывается так:
<prgname> [[Path\]Filename.wav]
Если параметров нет, она их запрашивает.
Вот её код(извините, что без комментов - надеюсь, принцип действия очевиден. Если у без них не понятно, скажите - я поясню):
Код

    org    80h
CmdLineLength:
    org    $+1
CmdLine:
    org    256
    mov    al,byte [CmdLineLength]
    cmp    al,1
    jbe    CmdLineEmpty
GetCmdLoop:
    mov    al,20h
    mov    cx,80h
    mov    di,CmdLine
    repe    scasb
    je    CmdLineEmpty
    dec    di
    cmp    byte [di],0dh
    je    CmdLineEmpty
    mov    dx,di
    mov    al,0dh
    repne    scasb
    jne    CmdLineEmpty
    dec    di
    mov    byte [di],0
    jmp    OpenFile
CmdLineEmpty:
    mov    ah,9
    mov    dx,PromptStr
    int    21h
    mov    ah,0ah
    mov    dx,FileNameStr
    mov    si,dx
    inc    si
    int    21h
    mov    ah,9
    mov    dx,CrLf
    int    21h
    mov    bl,byte [si]
    test    bl,bl
    jz    FileReadError
    mov    bh,0
    inc    si
    cmp    byte [bx+si],0dh
    jne    FileReadError
    mov    byte [bx+si],0
    mov    dx,FileName
OpenFile:
    mov    ax,3d00h
    int    21h
    jc    FileReadError
    mov    bx,ax
    mov    word [FileHandler],ax
    mov    ah,3fh
    mov    cx,24h
    mov    dx,FileBuffer
    mov    si,dx
    int    21h
    jc    FileReadError
    cmp    dword [si],"RIFF"
    jne    FormatError
    cmp    dword [si+8],"WAVE"
    jne    FormatError
    cmp    dword [si+0ch],"fmt "
    jne    FormatError
    cmp    word [si+14h],1
    jne    FormatError
    mov    edi,dword [si+18h]
    mov    cx,word [si+22h]
    cmp    cx,8
    jne    Is16Bit
    dec    byte [Instruction0ToMod]
    dec    byte [Instruction1ToMod]
    jmp    DoneSelfModifying
Is16Bit:
    cmp    cx,16
    jne    FormatError
DoneSelfModifying:
    mov    ax,word [si+20h]
    mov    word [BXIncrement],ax
    mov    ah,3fh
    mov    dx,FileBuffer
    mov    cx,8
    int    21h
    jc    FileReadError
    cmp    dword [si],"data"
    je    ParsingEnded
    mov    dx,word [si+4]
    mov    cx,word [si+6]
ReReadFile:
    mov    ax,4201h
    int    21h
    jc    FormatError
    mov    ah,3fh
    mov    cx,8
    mov    dx,FileBuffer
    int    21h
    jc    FileReadError
    cmp    dword [si],"data"
    je    ParsingEnded
    mov    dx,word [si+4]
    mov    cx,word [si+6]
    jmp    ReReadFile
ParsingEnded:
    push    0
    pop    ds
    mov    eax,dword [8*4]
    mov    word [8*4],IRQ0Handler
    mov    word [8*4+2],cs
    mov    ds,word [8*4+2]
    mov    dword [OldHandler],eax
LP:
    cmp    byte [Flag],1
    jne    LP
    mov    eax,dword [Freq]
    mov    edx,dword [Freq+4]
    mov    ecx,596590
    mov    ebx,32768
    mul    ecx
    div    ebx
    xor    edx,edx
    div    edi
    mov    ebp,eax
    mov    ah,9
    mov    dx,TipStr
    int    21h
    jmp    NewPart
MainLoop:
    mov    al,byte [temp]
    out    61h,al
EnterMainLoop:
    rdtsc
    mov    esi,eax
    mov    edi,edx
Instruction0ToMod:
    mov    dx,word [bx] ;8bh -> 8ah = word -> byte
    cmp    bx,cx
    ja    NewPart
    add    bx,word [BXIncrement]
    in    al,61h
    or    al,2
Instruction1ToMod:
    test    dx,dx ;85h -> 84h = word -> byte
    sets    ah
    add    ah,ah
    or    al,ah
    sub    ah,3
    and    al,ah
    mov    byte [temp],al
    mov    ah,1
    int    16h
    jnz    OutOfMainLoop
LP0:
    rdtsc
    sub    eax,esi
    sbb    edx,edi
    test    edx,edx
    jnz    MainLoop
    cmp    eax,ebp
    jb    LP0
    jmp    MainLoop
OutOfMainLoop:
    mov    ah,0
    int    16h
    retn
NewPart:
    mov    ah,3fh
    mov    bx,word [FileHandler]
    mov    cx,7ffch
    mov    dx,FileBuffer
    int    21h
    jc    FileReadError
    test    ax,ax
    jz    Exit
    mov    cx,ax
    add    cx,FileBuffer
    mov    bx,FileBuffer
    jmp    EnterMainLoop
FileReadError:
    mov    dx,FileReadErrorMessage
    jmp    CommonError
FormatError:
    mov    dx,FormatErrorMessage
CommonError:
    mov    ah,9
    push    cs
    pop    ds
    int    21h
Exit:
    retn
IRQ0Handler:
    pushad
    rdtsc
    push    ds
    push    cs
    pop    ds
    cmp    byte [Flag],0ffh
    jne    NotFF
    mov    byte [Flag],0
    jmp    IntRet
NotFF:
    sub    eax,dword [Freq]
    sbb    edx,dword [Freq+4]
    mov    byte [Flag],1
    mov    ecx,[OldHandler]
    push    0
    pop    ds
    mov    dword [8*4],ecx
IntRet:
    mov    dword [cs:Freq],eax
    mov    dword [cs:Freq+4],edx
    pop    ds
    mov    al,20h
    out    20h,al
    popad
    iret
FileReadErrorMessage:
    db    "Error reading file",13,10,24h
FormatErrorMessage:
    db    "Error parsing file"
CrLf:
    db    0dh,0ah,24h
PromptStr:
    db    "Enter file name (PCM WAV format)",13,10,24h
TipStr:
    db    "Press any key to stop playback & quit",13,10,24h
Flag:
    db    0ffh
FileNameStr:
    dw    254
FileName:
    org    $+255
temp:
    org    $+1
BXIncrement:
    org    $+2
Freq:
    org    $+8
OldHandler:
    org    $+4
FileHandler:
    org    $+2
FileBuffer:

Да, компилил я её с помощью FASM 1.65

Автор: xach 28.12.2007, 23:06
10110111

волшебная программа!  smile  ..очень юзабельна! =) спасибо

теперь вопросы:
 - как происходит временная синхронизация? (я в коде узрел rdtsc, подозреваю что с помощью неё, но подробности не помешают!)
 - какой код отвечает за установку и сброс спикера? (и про инициализацию его тоже оч интересно)

заранее мерси!

Автор: SABROG 29.12.2007, 00:17
Помню была у меня такая прога, работала только в досе, а жаль, вот бы юзер обкакался запустив какой-нибудь кейген в винде ;)

Автор: xach 30.12.2007, 04:35
итак, со спикером я разобрался, а вот с синхронизацией - нет.

очень бы хотелось повесить перезагрузку 2-го таймера на прерывание, а как это сделать гугл не говорит...возможен, конечно следующий вариант:
зная период 0-го таймера (18 с чем-то герц (при надобности легко узнать точное значение)) замерить его в тактах процессора (rdtsc) а потом ориентироваться чисто на rdtsc. получается точно, но не элегантно: прога постоянно зациклена и опрашивает tsc. 

В варианте же с прерыванием точность почти 100%, а затраты процессорного времени - минимальны (такую прогу можно даже резидентной сделать).

smile

З.Ы. всё, естественно под чистый dos.

Автор: xach 30.12.2007, 04:52
кстати, таймеров-то 3, а прерывание - одно...тоже не оч понятно...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)