Sadda.ru Ironetcart Андроид Ассемблер MASM32 Linux Все статьи Table of Contents


 

Воспоминание об Альгамбре на системном динамике

  Макс Петров май 2013

      Ниже приведенная программа показывает возможность контроля пользователем хода выполнения консольного приложения. В программе использованы вложенные макросы.

      Программа проигрывает композицию Ф.Тарреги "Воспоминание об Альгамбре". В отличие от ранее запрограммированного нами вальса Грибоедова, теперь мы сможем во время работы программы менять темп музыки, останавливать исполнение, перемещаться по произведению вперед или назад.

      В программу включены три не применявшиеся нами ранее API-функции: SetConsoleCursorPosition, SetConsoleTitle и Sleep.

      Function SetConsoleCursorPosition Lib "kernel32" Alias DWORD "SetConsoleCursorPosition" (DWORD hConsoleOutput, DWORD CursorPosition),
где hConsoleOutput - хэндл потока вывода консоли, CursorPosition - структура виндосовского типа COORD, содержащая координаты Y (0-25) X (0-79) курсора консоли. Функция устанавливает в заданную позицию курсор консоли, возвращает в EAX при успешном выполнении 1, при ошибке - 0.

тип данных COORD

      Переменные типа COORD имеют длину четыре байта, в младшем (нулевом) байте содержится значение горизонтальной координаты X, во втором байте - значение вертикальной координаты Y. Поскольку числа, содержащиеся во втором байте, в 65536 раз больше чисел, содержащихся в нулевом байте, мы можем задавать обе координаты в одной четырехбайтовой переменной типа COORD одним числом, выполняя несложное арифметическое действие, как показано на рисунке.

      Function SetConsoleTitle Lib "kernel32" Alias DWORD "SetConsoleTitleA" (DWORD lpConsoleTitle).
Функция содержится в библиотеке kernel32, ей передается единственный параметр - указатель на строку, которая должна завершаться нулем. Функция устанавливает заголовок консоли, возвращает в EAX при успешном выполнении 1, при ошибке - 0.

      Sub Sleep Lib "kernel32" Alias "Sleep" (DWORD dwMilliseconds).
Значений не возвращает, поэтому является, строго говоря, не функцией, а подпрограммой. Принимает от вызвавшей программы значение времени простоя в миллисекундах, освобождает ресурсы процессора от выполнения программы на заданное число миллисекунд.

.386 .model flat, stdcall option casemap :none include <\masm32\include\windows.inc> include <\masm32\include\kernel32.inc> include <\masm32\include\user32.inc> includelib <\masm32\lib\kernel32.lib> includelib <\masm32\lib\user32.lib> ; МАКРОС, ПРОИГРЫВАЮЩИЙ ЧЕТЫРЕ НОТЫ ++++++++++++++++++++++++++++++++++++++ tetr MACRO NumberOfLine, ; номер строки note, ; нота notetr, ; нота тремоло notem, ; нота мелизма vkl ; включатель мелизма peekconsole ; вызов макроса peekconsole writer NumberOfLine ; вызов макроса writer .if SetNumberOfLine == NumberOfLine invoke Beep, note, dur invoke Beep, notetr, dur invoke Beep, notetr, dur .if vkl invoke Beep, notem, dur .endif invoke Beep, notetr, dur .endif ENDM ; МАКРОС, ПРОИГРЫВАЮЩИЙ СТРОКУ НОТ +++++++++++++++++++++++++++++++++++++++ strk MACRO NumberOfLine, note1, note2, note3, note4, note5, note6, notetr1, notetr2, notetr3, notetr4, notetr5, notetr6, notem, vkl .if SetNumberOfLine == NumberOfLine tetr NumberOfLine, note1, notetr1, 0, 0 tetr NumberOfLine, note2, notetr2, notem, vkl tetr NumberOfLine, note3, notetr3, 0, 0 tetr NumberOfLine, note4, notetr4, 0, 0 tetr NumberOfLine, note5, notetr5, 0, 0 tetr NumberOfLine, note6, notetr6, 0, 0 inc SetNumberOfLine .endif ENDM ; МАКРОС, ПИШУЩИЙ В КОНСОЛИ ++++++++++++++++++++++++++++++++++++++++++++++ writer MACRO NumberOfLine invoke SetConsoleCursorPosition, hConOut, COORD_prog_cls invoke WriteConsoleA, hConOut, ADDR str_prog_cls, 57, ADDR nChars, 0 invoke SetConsoleCursorPosition, hConOut, COORD_progress invoke WriteConsoleA, hConOut, ADDR str_progress, NumberOfLine - 1, ADDR nChars, 0 invoke SetConsoleCursorPosition, hConOut, COORD_duration invoke WriteConsoleA, hConOut, ADDR str_duration, 14, ADDR nChars, 0 invoke SetConsoleCursorPosition, hConOut, COORD_line_num invoke WriteConsoleA, hConOut, ADDR str_line_num, 14, ADDR nChars, 0 ENDM ; МАКРОС, СЛЕДЯЩИЙ ЗА НАЖАТИЕМ ПОЛЬЗОВАТЕЛЕМ КЛАВИШ ++++++++++++++++++++++ peekconsole MACRO @@: ; локальная метка invoke PeekConsoleInputA, hConInp, ADDR buffinp, 1, ADDR nChars invoke FlushConsoleInputBuffer, hConInp .if buffinp[10] == 32 ; если "пробел", то крутимся в цикле jmp @B ; переход на локальную метку .endif .if buffinp[10] == 40 ; если "стрелка вниз", увеличиваем частоту inc dur .endif .if buffinp[10] == 38 ; если "стрелка вверх", уменьшаем частоту .if dur > 25 dec dur .endif .endif .if buffinp[10] == 37 ; если "стрелка влево", уменьшаем номер строки .if SetNumberOfLine >= 2 dec SetNumberOfLine dec SetNumberOfLine .elseif SetNumberOfLine >= 1 dec SetNumberOfLine .endif .endif .if buffinp[10] == 39 ; если "стрелка вправо", увеличиваем номер строки inc SetNumberOfLine .endif mov buffinp[10], 0 ; очищаем принимающий буфер converter dur, divider, \ str_duration[11], str_duration[12], str_duration[13] converter SetNumberOfLine, divider, \ str_line_num[11], str_line_num[12], str_line_num[13] ENDM ; МАКРОС, ПЕРЕВОДЯЩИЙ ЧИСЛО В ДЕСЯТИЧНОЕ И СИМВОЛЬНОЕ ПРЕДСТАВЛЕНИЕ +++++++ converter MACRO parametr, ; то, что переводится divider, ; делитель (10) byte1, byte2, byte3 ; байты для записи десятичных порядков mov EAX, parametr ; копируем в EAX DIV divider ; делим AX на байтовую переменную (10) mov byte3, AH ; копируем остаток от деления в byte3 mov AH, 0 ; обнуляем AH DIV divider ; делим AX на байтовую переменную (10) mov byte2, AH ; копируем остаток от деления в byte2 mov byte1, AL ; копируем частное в byte1 ADD byte1, 48 ; добавляем 48 - получаем символ цифры ADD byte2, 48 ADD byte3, 48 ENDM ; ######################################################################## .data hConInp DWORD ? ; переменная для хэндла потока ввода hConOut DWORD ? ; переменная для хэндла потока вывода nChars DWORD ? ; переменная для записи числа символов ConsTitle byte "Reminiscences Of Algambra", 0 ; заголовок консоли SetNumberOfLine dword 1 ; устанавливаемый номер строки воспроизведения buffinp byte 20 dup (0) ; буфер для записи сообщений консоли COORD_informer dword 10 * 65536 + 10 ; координаты начала строки str_informer COORD_prog_cls dword 20 * 65536 + 9 ; координаты начала строки str_prog_cls COORD_progress dword 20 * 65536 + 10 ; координаты начала строки str_progress COORD_duration dword 18 * 65536 + 10 ; координаты начала строки str_duration COORD_line_num dword 18 * 65536 + 51 ; координаты начала строки str_line_num str_informer byte "управление: стрелки вверх, вниз, влево, вправо, пробел", 0 str_prog_cls byte 43, 55 dup (32), 43 str_progress byte 79 dup (35) str_duration byte "duration = 075" str_line_num byte "line num = 001" dur dword 075 ; duration divider byte 10 ; делитель E1 dword 330 ; ми F1 dword 349 ; фа F1d dword 370 ; фа-диез G1 dword 392 ; соль G1d dword 415 ; соль-диез A1 dword 440 ; ля H1 dword 494 ; си C2 dword 523 ; до C2d dword 554 ; до-диез D2 dword 587 ; ре D2d dword 622 ; ре-диез E2 dword 660 ; ми F2 dword 698 ; фа F2d dword 740 ; фа-диез G2 dword 784 ; соль G2d dword 831 ; соль-диез A2 dword 880 ; ля H2 dword 988 ; си C3 dword 1047 ; до C3d dword 1109 ; до-диез D3 dword 1175 ; ре D3d dword 1245 ; ре-диез E3 dword 1319 ; ми F3 dword 1397 ; фа F3d dword 1480 ; фа-диез G3 dword 1568 ; соль G3d dword 1661 ; соль-диез A3 dword 1720 ; ля A3d dword 1867 ; ля-диез H3 dword 1976 ; си C4 dword 2093 ; до D4 dword 2349 ; ре ; ######################################################################## .code start: invoke AllocConsole ; запрашиваем у Windows консоль invoke SetConsoleTitle, ADDR ConsTitle invoke GetStdHandle, STD_INPUT_HANDLE ; получаем хэндл консоли для ввода mov hConInp, eax ; записываем хэндл в переменную invoke GetStdHandle, STD_OUTPUT_HANDLE ; получаем хэндл консоли для вывода mov hConOut, eax ; записываем хэндл в переменную invoke SetConsoleCursorPosition, hConOut, COORD_informer invoke CharToOem, ADDR str_informer, ADDR str_informer invoke WriteConsoleA, hConOut, ADDR str_informer, 54, ADDR nChars, 0 .while 1 ; НАЧАЛО БЕСКОНЕЧНОГО ЦИКЛА .if SetNumberOfLine == 1 invoke Sleep, 500 .endif strk 1, A1, E2, C3, E2, H2, E2, E3, E3, E3, E3, D3, D3, 0, 0 strk 2, A1, E2, A2, E2, H2, E2, C3, C3, C3, C3, D3, D3, 0, 0 strk 3, A1, E2, C3, E2, C3, E2, E3, E3, E3, E3, E3, E3, 0, 0 strk 4, A1, E2, C3, E2, D3, G2, E3, E3, E3, E3, F3, F3, 0, 0 strk 5, C2, G2, E3, G2, D3, G2, G3, G3, G3, G3, F3, F3, 0, 0 strk 6, C2, G2, C3, G2, D3, G2, E3, E3, E3, E3, F3, F3, 0, 0 strk 7, C2, G2, E3, G2, E3, G2, G3, G3, G3, G3, G3, G3, 0, 0 strk 8, C2, G2, E3, G2, E3, G2, G3, G3, G3, G3, G3, G3, 0, 0 strk 9, F2, C3, A3, C3, G3, C3, C4, C4, C4, C4, H3, H3, 0, 0 strk 10, F2, C3, F3, C3, D2, F3, A3, A3, A3, A3, H3, H3, 0, 0 strk 11, E1, H2, E3, H2, E3, H2, A3, A3, G3d, G3d, G3d, G3d, H3, 1 strk 12, E1, D3, E3, D3, E3, D3, G3d, G3d, G3d, G3d, G3d, G3d, 0, 0 strk 13, A1, C3d, E3, C3d, E3, C3d, A3d, A3d, A3d, A3d, A3, A3, 0, 0 strk 14, C2d, A2, E3, A2, F3, A2, G3, G3, G3, G3, A3, A3, 0, 0 strk 15, D2, E3, D3, A2, D3, A2, G3, G3, F3, F3, F3, F3, A3, 1 strk 16, D2, A2, D3, A2, D3, A2, F3, F3, F3, F3, F3, F3, 0, 0 strk 17, D2, A2, H2, A2, H2, A2, E3, E3, E3, E3, D3, D3, 0, 0 strk 18, F1, D2d, A2, D2d, A2, D2d, C3, C3, C3, C3, D3, D3, 0, 0 strk 19, E1, E2, G2d, E2, G2, E2, C3, C3, H2, H2, H2, H2, D3, 1 strk 20, E1, E2, G2d, E2, G2d, E2, H2, H2, H2, H2, H2, H2, 0, 0 strk 21, A1, E2, C3d, E2, H2, E2, E3, E3, E3, E3, D3, D3, 0, 0 strk 22, A1, E2, A2, E2, H2, E2, C3d, C3d, C3d, C3d, D3, D3, 0, 0 strk 23, A1, E2, C3d, E2, C3d, E2, E3, E3, E3, E3, E3, E3, 0, 0 strk 24, A1, E2, C3d, E2, C3d, E2, E3, E3, E3, E3, E3, E3, 0, 0 strk 25, A1, F2d, D3, F2d, D3, F2d, F3d, F3d, F3d, F3d, F3d, F3d, 0, 0 strk 26, A1, D3, H3, D3, D3, F2d, D4, D4, D4, D4, F3d, F3d, 0, 0 strk 27, A1, D3, C3d, E2, C3d, E2, F3d, F3d, E3, E3, E3, E3, G3d, 1 strk 28, A1, E2, C3d, E2, C3d, E2, E3, E3, E3, E3, E3, E3, 0, 0 strk 29, F1d, F2d, A2, C3d, A2, F2d, A3, A3, A3, A3, A3, A3, 0, 0 strk 30, G1d, G2d, C3, D3d, C3, G2d, G3d, G3d, G3d, G3d, D3d, D3d, 0, 0 strk 31, C2d, G2d, C3d, G2d, C3d, G2d, F3d, F3d, E3, E3, E3, E3, 0, 0 strk 32, C2d, G2d, C3d, G2d, C3d, G2d, E3, E3, E3, E3, E3, E3, 0, 0 strk 33, H1, F2, F2, D2, E2, F2, D3, D3, D3, D3, D3, D3, 0, 0 strk 34, E1, E2, E2, E2, E1, D2, C3d, C3d, C3d, C3d, H2, H2, 0, 0 strk 35, A1, E2, E2, E2, F2d, G2d, H2, H2, A2, A2, A2, A2, C3d, 1 strk 36, A1, E2, C2d, E2, A2, H2, A2, A2, A2, H2, C3d, D3, 0, 0 strk 37, A1, E2, E2, E2, E2, E2, A2, A2, A2, A2, A2, A2, 0, 0 strk 38, A1, F2, F2, F2, F2, F2, A2, A2, A2, A2, A2, A2, 0, 0 strk 39, A1, F2, A2, F2, A2, F2, H2, H2, C3d, C3d, D3, D3, 0, 0 strk 40, A1, E2, C3d, E2, C3d, E2, E3, E3, E3, E3, E3, E3, 0, 0 strk 41, A1, E2, C3d, E2, C3d, E2, E3, E3, E3, E3, E3, E3, 0, 0 strk 42, E1, G2d, G2d, G2d, G2d, G2d, E3, E3, E3, E3, E3, E3, 0, 0 strk 43, E1, F2d, E2, E2, E1, D2, D3, D3, C3d, C3d, H2, H2, 0, 0 strk 44, A1, E2, E2, F2, F2d, F2, A2, A2, A2, A2, A2, A2, 0, 0 strk 45, A1, E2, E2, E2, E2, E2, A2, A2, A2, A2, A2, A2, 0, 0 strk 46, A1, F2, F2, F2, F2, F2, A2, A2, A2, A2, A2, A2, 0, 0 strk 47, A1, F2, A2, F2, A2, F2, H2, H2, C2, C2, D2, D2, 0, 0 strk 48, A1, E2, C2d, E2, C3d, E2, E3, E3, E3, E3, E3, E3, 0, 0 strk 49, A1, E2, C2d, E2, C3d, E2, E3, E3, E3, E3, E3, E3, 0, 0 strk 50, E1, E2, E3, E2, E3, E2, G3d, G3d, G3d, G3d, G3d, G3d, 0, 0 strk 51, E1, E2, C3d, E2, H2, E2, F3d, F3d, E3, E3, D3, D3, 0, 0 strk 52, A1, E2, A2, E2, F2d, A2, C2d, C2d, C2d, C2d, C2d, C2d, 0, 0 strk 53, A1, E2, A2, E2, C2, C2d, C2d, C2d, C2d, C2d, C2d, C2d, 0, 0 strk 54, A1, E2, A2, E2, C2, C2d, C2d, C2d, C2d, C2d, C2d, C2d, 0, 0 ; предпоследний такт strk 55, A1, E2, A2, C3d, E3, A3, A1, E2, A2, C3d, E3, A3, 0, 0 strk 56, A1, 0, 0, 0, 0, 0, A1, A1, 0, 0, 0, 0, 0, 0 .if SetNumberOfLine > 56 mov SetNumberOfLine, 1 .elseif SetNumberOfLine < 1 mov SetNumberOfLine, 1 .endif .endw ; ВОЗВРАТ НА НАЧАЛО БЕСКОНЕЧНОГО ЦИКЛА invoke ExitProcess, 0 end start

      Выглядит вот так:

воспоминание об альгамбре на системном динамике

     


Добавить комментарий

E-mail:
*


Контрольные цифры:



Ассемблер MASM32

      Простейшая программа на ассемблере (beeper)
      Переменные и типы данных ассемблера
      Регистры процессора IA32
      Консоль ввода-вывода
      API-функция CharToOem и строки ассемблера
      API-функция ReadConsoleInput
      API-функция PeekConsoleInput
      События консоли (таблица)
      Системы счисления, тэги ассемблера, перевод чисел
      Отрицательные числа
      Инкремент и декремент
      Деление (DIV, IDIV)
      VKDEBUG
      Макросы ассемблера
      Воспоминание об Альгамбре на системном динамике
      Командная строка
      Пузырьковая сортировка. Эстафета шариков
      Сортировка расческой
      Быстрая сортировка

     


© Max Petrov При использовании материалов ссылка на sadda.ru обязательна