diff --git a/programs/media/Beat/Beat b/programs/media/Beat/Beat new file mode 100644 index 0000000000..720b2ca5d2 Binary files /dev/null and b/programs/media/Beat/Beat differ diff --git a/programs/media/Beat/Beat.c b/programs/media/Beat/Beat.c new file mode 100644 index 0000000000..bd7fbe6472 --- /dev/null +++ b/programs/media/Beat/Beat.c @@ -0,0 +1,544 @@ + +/* + * Author: JohnXenox aka Aleksandr Igorevich. + * + * Programme name: Beat + * Description: A simple metronome. + */ + +#include +#include +#include + +char header[] = "Beat 2020.05.17"; + +unsigned int skin_height = 0; + +unsigned int key = 0; +unsigned int btn = 0; + +short ctrl_keys_state = 0; + +int thread_stack = 0x1000; +int stack_size = 0x100; + + +char startButtonBit = 0; + +char tempoSelector = 0; + +short tempo = 100; // Beats Per Minute. + +char meter = 4; // 4/4 + +char accentBeatFlags[12] = {0}; + + +char counter = 1; + +counterIndicatorFlag = 0; + + +//Event mask bits for function 40. +enum EVENT_MASKS +{ + EVM_REDRAW = 0x00000001, + EVM_KEY = 0x00000002, + EVM_BUTTON = 0x00000004, + EVM_EXIT = 0x00000008, + EVM_BACKGROUND = 0x00000016, + EVM_MOUSE = 0x00000032, + EVM_IPC = 0x00000064, + EVM_STACK = 0x00000128, + EVM_DEBUG = 0x00000256, + EVM_STACK2 = 0x00000512, + EVM_MOUSE_FILTER = 0x80000000, + EVM_CURSOR_FILTER = 0x40000000 +}; + + + +enum EVENTS +{ + EVENT_REDRAW = 1, /* Window and window elements should be redrawn */ + EVENT_KEY = 2, /* A key on the keyboard was pressed */ + EVENT_BUTTON = 3, /* A button was clicked with the mouse */ + EVENT_MOUSE = 6 /* Mouse activity (movement, button press) was detected */ +}; + + +struct system_colors +{ + int frame; // color of frame. + int grab; // color of header. + int grab_button; // color of button on header bar. + int grab_button_text; // color of text on button on header bar. + int grab_text; // color of text on header. + int work; // color of working area. + int work_button; // color of button in working area. + int work_button_text; // color of text on button in working area. + int work_text; // color of text in working area. + int work_graph; // color of graphics in working area. +}; + + +struct system_colors sc; + +#include "Beat_lang.h" +#include "Beat_lib.h" + + +#define KEY_ARROW_UP 0xB2 +#define KEY_ARROW_DOWN 0xB1 +#define KEY_ARROW_LEFT 0xB0 +#define KEY_ARROW_RIGHT 0xB3 + +#define KEYS_CTRL_ARROW_UP 0x52 +#define KEYS_CTRL_ARROW_DOWN 0x51 +#define KEYS_CTRL_ARROW_LEFT 0x50 +#define KEYS_CTRL_ARROW_RIGHT 0x53 + +#define KEY_SPACE 0x20 + +#define KEY_ESCAPE 0x1B + +#define KEY_SLASH 0x2F + + + + +char redraw_flag = 0; + + +#define SMPL_NAME1 "Beep1.raw" +#define SMPL_NAME2 "Beep2.raw" +#define PRG_NAME "PlayNote" + +char _path_to_a_sample1[4096] = {0}; +char _path_to_a_sample2[4096] = {0}; +char _path_to_a_playnote[4096] = {0}; + +#define SEARCH_PATHES_NUMBER 3 + +unsigned char* search_pathes_to_a_playnote[] = { +_path_to_a_playnote, +"/sys/"PRG_NAME, +"/sys/Media/"PRG_NAME, +}; + +char *path_to_a_playnote = 0; + + + +int main(int argc, char** argv) +{ + setCurrentPathToARawFile(_path_to_a_sample1, argv[0], SMPL_NAME1); + setCurrentPathToARawFile(_path_to_a_sample2, argv[0], SMPL_NAME2); + setCurrentPathToARawFile(_path_to_a_playnote, argv[0], PRG_NAME); + + // searches for a PlayNote programme. + for(char i = 0; (i < SEARCH_PATHES_NUMBER); i++) + { + if(startApp("/sys/loool.raw", 0, search_pathes_to_a_playnote[i]) > 0) + { + path_to_a_playnote = search_pathes_to_a_playnote[i]; + } + } + + if(path_to_a_playnote == 0) + { + #if defined (lang_en) + startApp("\"Can't find a PlayNote programme!\" -W", 0, "/sys/@notify"); + #elif defined (lang_ru) + startApp("\" ணࠬ PlayNote!\" -W", 0, "/sys/@notify"); + #endif + + return 1; + } + + _ksys_set_wanted_events(EVM_REDRAW | EVM_KEY | EVM_BUTTON | EVM_MOUSE_FILTER); + + + + + + drawWindow(); + + for (;;) + { + + if(startButtonBit == 1) + { + + if(redraw_flag == 0) + { + + //if(counter == 0) counter++; + + if(counter < meter) + counter++; + else if(counter == meter) + counter = 1; + + + + if(accentBeatFlags[counter - 1] == 0) + { + // play a beep sound. + startApp(_path_to_a_sample2, 0, path_to_a_playnote); + } + else + { + // play a beep sound. + startApp(_path_to_a_sample1, 0, path_to_a_playnote); + } + + + + + showCounterIndicator(); + + +// makeDelay(7); + + } + else + { + redraw_flag = 0; + } + + } + + switch(_ksys_wait_for_event(6000 / (tempo))) + { + case EVENT_REDRAW: + + redraw_flag = 1; + + drawWindow(); + break; + + case EVENT_KEY: + ctrl_keys_state = getControlKeysOnAKeyboard(); + + // key pressed, read it and ignore + key = _ksys_get_key(); + + key = ((key >> 8) & 0x000000FF); + + + //printfOnADebugBoard("ctrl_keys_state: %d\n", ctrl_keys_state); + + // makes exit. + if(key == KEY_ESCAPE) return 0; + + // starts beats. + if(key == KEY_SPACE) + { + if(startButtonBit == 0) + startButtonBit = 1; + else + startButtonBit = 0; + + showStartButton(); + } + + + // decreases tempo. + if(key == KEY_ARROW_LEFT) + { + if(tempo != 1) + { + showTempoBar2(--tempo); + setTempoSelectorByTempo(&tempo, &tempoSelector); + + } + } + + // increases tempo. + if(key == KEY_ARROW_RIGHT) + { + if(tempo != 320) + { + showTempoBar2(++tempo); + setTempoSelectorByTempo(&tempo, &tempoSelector); + } + } + + + // decreases a tempo selector. + if(key == KEYS_CTRL_ARROW_LEFT) + { + if ((ctrl_keys_state == 4) || (ctrl_keys_state == 8)) + { + if(tempoSelector != 0) + { + showTempoBar1(--tempoSelector); + setTempoByTempoSelector(&tempo, tempoSelector); + showTempoBar2(tempo); + } + } + } + + + // increases a tempo selector. + if(key == KEYS_CTRL_ARROW_RIGHT) + { + if ((ctrl_keys_state == 4) || (ctrl_keys_state == 8)) + { + if(tempoSelector != 9) + { + showTempoBar1(++tempoSelector); + setTempoByTempoSelector(&tempo, tempoSelector); + showTempoBar2(tempo); + } + } + } + + + if(key == 0x2C) + { + if(meter > 1) + { + showMeterBar(--meter); + showMeterIndicator(); + } + + } + + if(key == 0x2E) + { + if(meter < 12) + { + showMeterBar(++meter); + showMeterIndicator(); + } + } + + + for(unsigned char i = 0; i < 9; i++) + { + if(key == (0x31 + i)) + { + if(accentBeatFlags[i] == 0) + { + accentBeatFlags[i] = 1; + } + else if (accentBeatFlags[i] != 0) + { + accentBeatFlags[i] = 0; + } + + + showMeterIndicator(); + } + } + + if(key == 0x30) + { + if(accentBeatFlags[9] == 0) + accentBeatFlags[9] = 1; + else if (accentBeatFlags[9] != 0) + accentBeatFlags[9] = 0; + + showMeterIndicator(); + } + + if(key == 0x2D) + { + if(accentBeatFlags[10] == 0) + accentBeatFlags[10] = 1; + else if (accentBeatFlags[10] != 0) + accentBeatFlags[10] = 0; + + showMeterIndicator(); + } + + if(key == 0x3D) + { + if(accentBeatFlags[11] == 0) + accentBeatFlags[11] = 1; + else if (accentBeatFlags[11] != 0) + accentBeatFlags[11] = 0; + + showMeterIndicator(); + } + + + + + // invertation of colours. + if(key == KEY_SLASH) + { + if(counterIndicatorFlag != 0) + counterIndicatorFlag = 0; + else if (counterIndicatorFlag == 0) + counterIndicatorFlag = 1; + + showCounterIndicator(); + } + + + break; + + case EVENT_BUTTON: + // button pressed; we have only one button, close + btn = _ksys_get_button_id(); + + if(btn == 1) return 0; + + if(btn == 7) + { + + if(startButtonBit == 0) + startButtonBit = 1; + else + startButtonBit = 0; + + showStartButton(); + } + + + // decreases a tempo selector. + if(btn == 10) + { + if(tempoSelector != 0) + { + showTempoBar1(--tempoSelector); + setTempoByTempoSelector(&tempo, tempoSelector); + showTempoBar2(tempo); + } + } + + + // increases a tempo selector. + if(btn == 11) + { + if(tempoSelector != 9) + { + showTempoBar1(++tempoSelector); + setTempoByTempoSelector(&tempo, tempoSelector); + showTempoBar2(tempo); + } + } + + + // decreases tempo. + if(btn == 12) + { + if(tempo != 1) + { + showTempoBar2(--tempo); + setTempoSelectorByTempo(&tempo, &tempoSelector); + + } + } + + + // increases tempo. + if(btn == 13) + { + if(tempo < 320) + { + showTempoBar2(++tempo); + setTempoSelectorByTempo(&tempo, &tempoSelector); + } + } + + + if(btn == 14) + { + if(meter > 1) + { + showMeterBar(--meter); + + // clreans unused flags. + for(unsigned char i = meter; i < 11; i++) + { + accentBeatFlags[i] = 0; + } + + //if(meter == 1) accentBeatFlags[0] = 0; + + + showMeterIndicator(); + } + + } + + if(btn == 15) + { + if(meter < 12) + { + showMeterBar(++meter); + + // clreans unused flags. + for(unsigned char i = meter; i < 11; i++) + { + accentBeatFlags[i] = 0; + } + + showMeterIndicator(); + } + + } + + + for(unsigned char i = 0; i < 12; i++) + { + if(btn == (100 + i)) + { + //if(meter > 1) + //{ + if(accentBeatFlags[i] == 0) + { + accentBeatFlags[i] = 1; + } + else if (accentBeatFlags[i] != 0) + { + accentBeatFlags[i] = 0; + } + //} + //else if(meter == 1) accentBeatFlags[i] = 0; + + showMeterIndicator(); + } + } + + + if(btn == 200) + { + if(counterIndicatorFlag != 0) + counterIndicatorFlag = 0; + else if (counterIndicatorFlag == 0) + counterIndicatorFlag = 1; + + showCounterIndicator(); + } + + + + break; + + } + } +} + + + + + + + + + + + + + + + + + + + diff --git a/programs/media/Beat/Beat.gif b/programs/media/Beat/Beat.gif new file mode 100644 index 0000000000..d2899f6626 Binary files /dev/null and b/programs/media/Beat/Beat.gif differ diff --git a/programs/media/Beat/Beat_lang.h b/programs/media/Beat/Beat_lang.h new file mode 100644 index 0000000000..0d7eb24ec6 --- /dev/null +++ b/programs/media/Beat/Beat_lang.h @@ -0,0 +1,3 @@ + +//#define lang_ru +#define lang_en diff --git a/programs/media/Beat/Beat_lib.h b/programs/media/Beat/Beat_lib.h new file mode 100644 index 0000000000..a30ba11def --- /dev/null +++ b/programs/media/Beat/Beat_lib.h @@ -0,0 +1,732 @@ + +/* + * Beat_lib.h + * Author: JohnXenox aka Aleksandr Igorevich. + */ + +#ifndef __Beat_lib_h__ +#define __Beat_lib_h__ + + +void __attribute__ ((noinline)) printfOnADebugBoard(const char *format,...) +{ + va_list ap; + char log_board[300]; + + va_start (ap, format); + tiny_vsnprintf(log_board, sizeof log_board, format, ap); + va_end(ap); + + char *str = log_board; + + while(*str) __asm__ __volatile__("int $0x40"::"a"(63), "b"(1), "c"(*str++)); +} + + +/* +int start_new_thread(void* proc, unsigned int* stack_top) +{ + register int val; + __asm__ __volatile__("int $0x40":"=a"(val):"a"(51), "b"(1), "c"(proc), "d"(stack_top)); + return val; +} +*/ + + +static inline int startApp(char *args, unsigned int enc, char *path) +{ + int val; + + char dt[28]; // basic information structure. + + (int ) dt[0] = 7; // subfunction number. + (int ) dt[4] = 0; // flags field. + (char*) dt[8] = args; // 0 or pointer to ASCIIZ-string with parameters. + (int ) dt[12] = 0; // (reserved). + (int ) dt[16] = 0; // (reserved). + (int ) dt[20] = 1; // string encoding (0 = default, 1 = cp866, 2 = UTF-16LE, 3 = UTF-8). + (char*) dt[24] = path; // pointer to the path to the file. + + __asm__ __volatile__("int $0x40":"=a"(val):"a"(80), "b"(&dt)); + + return val; +} + + + +static inline void makeDelay(unsigned int time) +{ + __asm__ __volatile__("int $0x40"::"a"(5), "b"(time):"memory"); +} + + + +static inline void getSystemColors(struct system_colors *color_table) +{ + __asm__ volatile ("int $0x40"::"a"(48),"b"(3),"c"(color_table),"d"(40)); +} + + + +static inline short getControlKeysOnAKeyboard(void) +{ + short val; + __asm__ __volatile__("int $0x40":"=a"(val):"a"(66),"b"(3)); + return val; +} + + +static inline void showButton(int x, int y, int w, int h, unsigned int style, unsigned int id, unsigned int clr) +{ + w-=1; + h-=1; + __asm__ __volatile__("int $0x40"::"a"(8),"b"((x << 16) | w),"c"((y << 16) | h),"d"((style << 24) | id),"S"(clr)); +} + + + +static inline void deleteButton(unsigned int id) +{ + __asm__ __volatile__("int $0x40"::"a"(8),"d"(0x80000000 | id)); +} + + + +static inline void showNumber(int x, int y, unsigned int opt1, unsigned char opt2, unsigned int clr, unsigned int number) +{ + __asm__ __volatile__("int $0x40"::"a"(47),"b"(opt1),"c"(number),"d"((x << 16) | y),"S"(clr | ((int) opt2 << 24))); +} + + + +/* +static inline void killThreadByTID(int tid) +{ + __asm__ __volatile__("int $0x40"::"a"(18), "b"(18), "c"(tid)); +} +*/ + + +static inline void showLine(int xs, int ys, int xe, int ye, unsigned int clr) +{ + __asm__ __volatile__("int $0x40"::"a"(38), "d"(clr),"b"((xs << 16) | xe),"c"((ys << 16) | ye)); +} + + + + + + + + + + + +// ============================================================================ // + +void showRectangle(int x, int y, int w, int h, unsigned int clr) +{ + // top h line. + showLine(x + 1, y, w + x - 2, y, clr); + // bottom h line. + showLine(x + 1, y + h - 1, w + x - 2, y + h - 1, clr); + + // left v line. + showLine(x, y + 1, x, h + y - 2, clr); + // right v line. + showLine(x + w - 1, y + 1, x + w - 1, h + y - 2, clr); +} + + + +static inline void setCurrentPathToARawFile(char *dst_path, char *src_path, char* file_name) +{ + unsigned offset = 0; + + // cleans a dst path if not clean. + if(dst_path[offset] != 0) + { + for(; dst_path[offset] != 0; offset++) dst_path[offset] = 0; + } + + // copys current path into a buffer. + strcpy(dst_path, src_path); + + offset = 0; + + // goes to the end of a string. + while(dst_path[offset] != 0) offset++; + + // clears all bytes to a character '/'. + for(; dst_path[offset] != '/'; offset--) dst_path[offset] = 0; + + // increments a variable. + offset++; + + // stores a name of a file in a buffer. + strcpy(dst_path + offset, file_name); +} + + + +static inline void showNamedButton(int x, int y, int w, int h, int style, int id, int clr, \ + char font_style, int tx, int ty, unsigned int text_clr, \ + unsigned int text_len, char* text) +{ +// w--; +// h--; + + char chr_w = 8; + char chr_h = 16; + + deleteButton(id); + _ksys_make_button(x, y, (w - 1), (h - 1), (style | id), clr); + _ksys_write_text((x + ((w / 2) - ((chr_w * text_len) / 2))), (y + 1 + ((h / 2) - (chr_h / 2))), \ + (((int)font_style << 24) | text_clr), text, text_len); + +} + + +static inline void StartButton(int x, int y, int w, int h, unsigned int clr, unsigned int text_clr, unsigned char state) +{ + #define BTN_ID 7 + +#if defined (lang_en) + char* btn_name[] = {"Start", "Stop"}; +#elif defined (lang_ru) + char* btn_name[] = {"", "⮯"}; +#endif + + showNamedButton(x, y, w, h, 0, BTN_ID, clr, 0b00010000, 2, 2, text_clr, strlen(btn_name[state]), btn_name[state]); + + if(state == 1) counter = 0; + + #undef BTN_ID +} + + + +static inline void showPlusButton(int x, int y, int w, int h, unsigned int id, unsigned int clr, unsigned int text_clr) +{ + showNamedButton(x, y, w, h, 0, id, clr, 0b00010000, 2, 2, text_clr, 1, "+"); +} + + + +static inline void showMinusButton(int x, int y, int w, int h, unsigned int id, unsigned int clr, unsigned int text_clr) +{ + showNamedButton(x, y, w, h, 0, id, clr, 0b00010000, 2, 2, text_clr, 1, "-"); +} + +//===================================================================================// + + + + + + + + + +void counterIndicator(int x, int y, int w, int h, unsigned int clr1, unsigned int clr2, unsigned char flag) +{ + #define BTN_ID 200 + + unsigned int _clr1; + unsigned int _clr2; + + char chr_w = 8 * 3; + char chr_h = 16 * 3; + + unsigned char text_len = 1; + + deleteButton(BTN_ID); + _ksys_make_button(x, y, w - 1, h - 1, (0x40000000 | BTN_ID), clr1); + + + if(flag == 0) + { + _clr1 = clr1; + _clr2 = clr2; + } + if(flag != 0) + { + _clr1 = clr2; + _clr2 = clr1; + } + + showRectangle(x, y, w, h, _clr2); + _ksys_draw_bar((x + 1), (y + 1), (w - 2), (h - 2), _clr1); + + if(counter > 9) text_len = 2; + + showNumber((x + ((w / 2) - ((chr_w * text_len) / 2))), ((y + ((h / 2) - (chr_h / 2))) - 4), 0b10000000000000110000000000000000, 0b00010011, _clr2, counter); + + #undef BTN_ID +} + + + + + +void meterIndicator(int x, int y, int w, int h, unsigned int clr1, unsigned int clr2, unsigned char meter, unsigned char *accentBeatFlags) +{ + #define SPACE 2 + + #define BTN_ID 100 + + char chr_w = 8; + char chr_h = 16; + + int text_len = 1; + + unsigned int btn_clr = 0; + unsigned int num_clr = 0; + + _ksys_draw_bar(10, y, w + 5, h, sc.work); + + // deletes all possible buttons. + for(unsigned short i = 0; (i < 12); i++) + { + deleteButton(BTN_ID + i); + } + + + unsigned char num_of_spaces = 0; + unsigned short spaces_sz = 0; + + unsigned int btn_x = x; + unsigned int btn_w = w; + + + +//===========================================// + + char spc = 0; + + if(meter > 1) + { + spc = 1; + num_of_spaces = (meter - 1); + spaces_sz = (num_of_spaces * SPACE); + } + + btn_w = ((btn_w / meter) - spc); + +//===========================================// + + + + + + + + + // draws button(s). + for(unsigned short i = 0; (i < meter); i++) + { + if((i + 1) > 9) text_len = 2; + + if(accentBeatFlags[i] == 0) + { + btn_clr = clr1; + num_clr = clr2; + } + else + { + btn_clr = clr2; + num_clr = clr1; + } + + showButton(btn_x, y, btn_w, h, 0, (BTN_ID + i), btn_clr); + //_ksys_make_button(btn_x, y, (btn_w - 1), (h - 1), (0 | (BTN_ID + i)), btn_clr); + showNumber(((btn_x + ((btn_w / 2) - ((chr_w * text_len) / 2)))), (y + 2 + ((h / 2) - (chr_h / 2))), 0b10000000000000110000000000000000, 0b00010000, num_clr, (i + 1)); + + btn_x += (btn_w + SPACE); + } + + #undef SPACE + #undef BTN_ID +} + + + +void tempoBar1(int x, int y, int w, int h, unsigned int clr1, unsigned int clr2, unsigned int clr3, unsigned char sel) +{ + #define BTN_ID_MINUS 10 + #define BTN_ID_PLUS 11 + + char chr_w = 8; + char chr_h = 16; + + char* text = 0; + int text_len = 0; + + char* tempoIt[] = {"Larghissimo", "Grave", "Lento", "Larghetto", "Adagio", "Andante", \ + "Moderato", "Allegro", "Presto", "Prestissimo"}; + + _ksys_draw_bar((x + 1), y, (w - 2), h, clr1); + + text = tempoIt[sel]; + text_len = strlen(tempoIt[sel]); + + _ksys_write_text((x + ((w / 2) - ((chr_w * text_len) / 2))), (y + 0 + ((h / 2) - (chr_h / 2))), (((int)0b00010000 << 24) | clr2), text, text_len); + + showMinusButton(x, y, h, h, BTN_ID_MINUS, clr3, clr2); + showPlusButton(((x + w) - h), y, h, h, BTN_ID_PLUS, clr3, clr2); + + #undef BTN_ID_MINUS + #undef BTN_ID_PLUS +} + + + +void tempoBar2(int x, int y, int w, int h, unsigned int clr1, unsigned int clr2, unsigned int clr3, unsigned short tempo) +{ + #define BTN_ID_MINUS 12 + #define BTN_ID_PLUS 13 + + char chr_w = 8; + char chr_h = 16; + + int text_len = 0; + + if(tempo < 10) + { + text_len = 1; + } + else if((tempo > 9) && (tempo < 100)) + { + text_len = 2; + } + else if((tempo > 99) && (tempo < 321)) + { + text_len = 3; + } + + _ksys_draw_bar((x + 1), y, (w - 2), h, clr1); + + showNumber((x + ((w / 2) - ((chr_w * text_len) / 2))), (y + ((h / 2) - (chr_h / 2))), 0b10000000000000110000000000000000, 0b00010000, clr2, tempo); + + showMinusButton(x, y, h, h, BTN_ID_MINUS, clr3, clr2); + showPlusButton(((x + w) - h), y, h, h, BTN_ID_PLUS, clr3, clr2); + + #undef BTN_ID_MINUS + #undef BTN_ID_PLUS +} + + + +void meterBar(int x, int y, int w, int h, unsigned int clr1, unsigned int clr2, unsigned int clr3, unsigned char meter, unsigned int divider) +{ + #define BTN_ID_MINUS 14 + #define BTN_ID_PLUS 15 + + char chr_w = 8; + char chr_h = 16; + + int text_len = 3; + + if(meter > 9) text_len = 4; + + _ksys_draw_bar((x + 1), y, (w - 2), h, clr1); + + unsigned int num_x = ((x + ((w / 2) - ((chr_w * text_len) / 2)))); + unsigned int num_y = (y + ((h / 2) - (chr_h / 2))); + + showNumber(num_x, num_y, 0b10000000000000110000000000000000, 0b00010000, clr2, meter); + _ksys_write_text((num_x + (chr_w * (text_len - 2))), num_y, (((int)0b00010000 << 24) | clr2), "/", 1); + showNumber((num_x + (chr_w * (text_len - 1))), num_y, 0b10000000000000110000000000000000, 0b00010000, clr2, 4); + + showMinusButton(x, y, h, h, BTN_ID_MINUS, clr3, clr2); + showPlusButton(((x + w) - h), y, h, h, BTN_ID_PLUS, clr3, clr2); + + #undef BTN_ID_MINUS + #undef BTN_ID_PLUS +} + + + +//===================================================================// + +void showCounterIndicator() +{ + counterIndicator(10, (skin_height + 5), 310, 60, sc.work_button, sc.work_button_text, counterIndicatorFlag); +} + + + +void showMeterIndicator() +{ + meterIndicator(10, (skin_height + 70), 310, 21, sc.work_button, sc.work_button_text, meter, accentBeatFlags); +} + + + + + +void showTempoBar1(char tempoSelector) +{ + tempoBar1(10, (skin_height + 96), 140, 20, sc.work_graph, sc.work_button_text, sc.work_button, tempoSelector); +} + + + +void showTempoBar2(short tempo) +{ + tempoBar2((10 + 145), (skin_height + 96), 76, 20, sc.work_graph, sc.work_button_text, sc.work_button, tempo); +} + + + +void showMeterBar(char meter) +{ + meterBar((10 + 140 + 5 + 76 + 5), (skin_height + 96), 84, 20, sc.work_graph, sc.work_button_text, sc.work_button, meter, 4); +} + + + +void showStartButton(void) +{ + StartButton(10, (skin_height + 121), 310, 25, sc.work_button, sc.work_button_text, startButtonBit); +} + +//================================================================================// + + + + + + + + +void setTempoByTempoSelector(unsigned short *tempo, unsigned char tempoSelector) +{ + enum tempoSelectors + { + LARGHISSIMO = 0, + GRAVE, + LENTO, + LARGHETTO, + ADAGIO, + ANDANTE, + MODERATO, + ALLEGRO, + PRESTO, + PRESTISSIMO + }; + + // switches tempo (beats per minet). + switch(tempoSelector) + { + case LARGHISSIMO: *tempo = 20; // 1 - 25 bpm. + break; + + case GRAVE: *tempo = (46 - ((46 - 25) / 2)); // 25 - 46 bpm. calculates an average value. + break; + + case LENTO: *tempo = (61 - ((61 - 46) / 2)); // 46 - 61 bpm + break; + + case LARGHETTO: *tempo = (67 - ((67 - 61) / 2)); + break; + + case ADAGIO: *tempo = (77 - ((77 - 67) / 2)); + break; + + case ANDANTE: *tempo = (109 - ((109 - 77) / 2)); + break; + + case MODERATO: *tempo = (121 - ((121 - 109) / 2)); + break; + + case ALLEGRO: *tempo = (169 - ((169 - 121) / 2)); + break; + + case PRESTO: *tempo = (201 - ((201 - 169) / 2)); + break; + + case PRESTISSIMO: *tempo = (320 - ((320 - 201) / 2)); + break; + } +} + + + + + +void setTempoSelectorByTempo(unsigned short *tempo, unsigned char *tempoSelector) +{ + enum tempoSelectors + { + LARGHISSIMO = 0, + GRAVE, + LENTO, + LARGHETTO, + ADAGIO, + ANDANTE, + MODERATO, + ALLEGRO, + PRESTO, + PRESTISSIMO + }; + + // switches a selector. + if((*tempo > 0) && (*tempo < 25)) + { + if(*tempoSelector != LARGHISSIMO) + { + *tempoSelector = LARGHISSIMO; + showTempoBar1(*tempoSelector); + } + } + else if((*tempo >= 25) && (*tempo < 46)) + { + if(*tempoSelector != GRAVE) + { + *tempoSelector = GRAVE; + showTempoBar1(*tempoSelector); + } + } + else if((*tempo >= 46) && (*tempo < 61)) + { + if(*tempoSelector != LENTO) + { + *tempoSelector = LENTO; + showTempoBar1(*tempoSelector); + } + } + else if((*tempo >= 61) && (*tempo < 67)) + { + if(*tempoSelector != LARGHETTO) + { + *tempoSelector = LARGHETTO; + showTempoBar1(*tempoSelector); + } + } + else if((*tempo >= 67) && (*tempo < 77)) + { + if(*tempoSelector != ADAGIO) + { + *tempoSelector = ADAGIO; + showTempoBar1(*tempoSelector); + } + } + else if((*tempo >= 77) && (*tempo < 109)) + { + if(*tempoSelector != ANDANTE) + { + *tempoSelector = ANDANTE; + showTempoBar1(*tempoSelector); + } + } + else if((*tempo >= 109) && (*tempo < 121)) + { + if(*tempoSelector != MODERATO) + { + *tempoSelector = MODERATO; + showTempoBar1(*tempoSelector); + } + } + else if((*tempo >= 121) && (*tempo < 169)) + { + if(*tempoSelector != ALLEGRO) + { + *tempoSelector = ALLEGRO; + showTempoBar1(*tempoSelector); + } + } + else if((*tempo >= 169) && (*tempo < 201)) + { + if(*tempoSelector != PRESTO) + { + *tempoSelector = PRESTO; + showTempoBar1(*tempoSelector); + } + } + else if((*tempo >= 201) && (*tempo < 321)) + { + if(*tempoSelector != PRESTISSIMO) + { + *tempoSelector = PRESTISSIMO; + showTempoBar1(*tempoSelector); + } + } +} + + +void drawWindow() +{ + //if(counter > 1) counter = 1; + + getSystemColors(&sc); + skin_height = _ksys_get_skin_height(); + + _ksys_window_redraw(1); + _ksys_draw_window(10, 10, 330, 200, sc.work, 0x14, 0x5080d0, 0, (int)header); + _ksys_window_redraw(2); + + + showCounterIndicator(); + + showMeterIndicator(); + + setTempoSelectorByTempo(&tempo, &tempoSelector); + + showTempoBar1(tempoSelector); + showTempoBar2(tempo); + showMeterBar(meter); + showStartButton(); + + //int a_x = ((x + ((w / 2) - ((chr_w * text_len) / 2))) - num_offset); + + #if defined (lang_en) + _ksys_write_text(94, (skin_height + 153), (((int)0b10010000 << 24) | sc.work_text), "Author: JohnXenox", 0); + #elif defined (lang_ru) + _ksys_write_text(94, (skin_height + 153), (((int)0b10010000 << 24) | sc.work_text), ": JohnXenox", 0); + #endif + + + +//showRectangle(10, (skin_height + 5), 315, 50, 0xff0000); + +} + + + +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/programs/media/Beat/Beep1.raw b/programs/media/Beat/Beep1.raw new file mode 100644 index 0000000000..2dfd5520a6 Binary files /dev/null and b/programs/media/Beat/Beep1.raw differ diff --git a/programs/media/Beat/Beep2.raw b/programs/media/Beat/Beep2.raw new file mode 100644 index 0000000000..47f3d6c3b1 Binary files /dev/null and b/programs/media/Beat/Beep2.raw differ diff --git a/programs/media/Beat/Build.sh b/programs/media/Beat/Build.sh new file mode 100644 index 0000000000..c2ad276795 --- /dev/null +++ b/programs/media/Beat/Build.sh @@ -0,0 +1,3 @@ +#SHS +tcc Beat.c -o Beat -lck +exit diff --git a/programs/media/Beat/History.txt b/programs/media/Beat/History.txt new file mode 100644 index 0000000000..c40fb7a3bc --- /dev/null +++ b/programs/media/Beat/History.txt @@ -0,0 +1,4 @@ +History: + +Beat 2020.05.17 + First release. \ No newline at end of file diff --git a/programs/media/Beat/PlayNote/Build.sh b/programs/media/Beat/PlayNote/Build.sh new file mode 100644 index 0000000000..be3e818d89 --- /dev/null +++ b/programs/media/Beat/PlayNote/Build.sh @@ -0,0 +1,3 @@ +#SHS +tcc PlayNote.c -o PlayNote -lck +exit diff --git a/programs/media/Beat/PlayNote/History.txt b/programs/media/Beat/PlayNote/History.txt new file mode 100644 index 0000000000..84da6e476e --- /dev/null +++ b/programs/media/Beat/PlayNote/History.txt @@ -0,0 +1,13 @@ +History: + +PlayNote 2020.05.17 + Code optimization. + +PlayNote 2020.05.07 + First release. + + + + + + diff --git a/programs/media/Beat/PlayNote/PlayNote b/programs/media/Beat/PlayNote/PlayNote new file mode 100644 index 0000000000..b8c685d748 Binary files /dev/null and b/programs/media/Beat/PlayNote/PlayNote differ diff --git a/programs/media/Beat/PlayNote/PlayNote.c b/programs/media/Beat/PlayNote/PlayNote.c new file mode 100644 index 0000000000..8900c9cf28 --- /dev/null +++ b/programs/media/Beat/PlayNote/PlayNote.c @@ -0,0 +1,114 @@ + +/* + * Author: JohnXenox aka Aleksandr Igorevich. + * + * Programme name: PlayNote + * Description: The programme to play a note. + * + * Works from command line, only! +*/ + +// To generate .wav file with sox (to listen): +// sox -n -L -c 1 -b 16 -r 48000 Note_C5.wav synth 1 sine 1046.4 +// To generate .raw file with sox (to PlayNote): +// sox -n -L -c 1 -b 16 -r 48000 Note_C5.raw synth 1 sine 1046.4 + +#define CREATION_DATE "2020.05.17" + +#include +#include +#include + +#include "PlayNote_lib1.h" +#include "PlayNote_lib2.h" + + +unsigned int drv_ver = 0; +unsigned int buffer = 0; + +unsigned int *raw_file_data = 0; + +char raw_file[4096] = {0}; + + + +int main(int argc, char** argv) +{ +// ============================================================ // +// checks memory availability ================================= // + + if(initMemory() == 0) return -1; + +// ============================================================ // +// sets a current path to a raw file ========================== // + + //setCurrentPathToARawFile(raw_file, argv[0], "Note_C6_0.5.raw"); + +_ksys_set_wanted_events(0); + +// ============================================================ // +// processes the command line arguments ======================= // + + if (argc > 1) + { + //printfOnADebugBoard("ARGV1: %s\n", argv[1]); + strcpy(raw_file, argv[1]); + + // checks to a full path to a file? + if(*argv[1] != '/') + { + setCurrentPathToARawFile(raw_file, argv[0], argv[1]); + } + } + else + { + if (con_init_console_dll()) return 1; // init fail + + con_set_title("Useful info!"); + + con_printf("\n Name: PlayNote"); + con_printf("\n Date: %s", CREATION_DATE); + con_printf("\n Description: The programme to play a note.\n"); + + con_printf("\n Author: JohnXenox\n"); + + con_printf("\n Usage: PlayNote \n"); + con_printf(" path - path to a file to be played.\n\n"); + + con_printf(" Examples:\n"); + con_printf(" PlayNote note.raw\n"); + con_printf(" PlayNote /tmp0/1/note.raw\n"); + + return 0; + } + + //printfOnADebugBoard("raw_file path: %s\n", argv[1]); + +// ============================================================ // +// plays a note =============================================== // + + int raw_file_length = 0; + raw_file_data = openFile(&raw_file_length,raw_file); + if(raw_file_data == 0) return -2; + + _InitSound(&drv_ver); + _CreateBuffer((PCM_STATIC | PCM_1_16_48), raw_file_length, &buffer); + _SetBuffer((int*)buffer, (int*)raw_file_data, 0, raw_file_length); + _SetBufferPos((int*)buffer, 0); + + _PlayBuffer((int*)buffer, 0); + + makeDelay(30); + + _StopBuffer((int*)buffer); + + return 0; +} + + + + + + + + diff --git a/programs/media/Beat/PlayNote/PlayNote.png b/programs/media/Beat/PlayNote/PlayNote.png new file mode 100644 index 0000000000..56da936fee Binary files /dev/null and b/programs/media/Beat/PlayNote/PlayNote.png differ diff --git a/programs/media/Beat/PlayNote/PlayNote_lib1.h b/programs/media/Beat/PlayNote/PlayNote_lib1.h new file mode 100644 index 0000000000..7dfd4b488e --- /dev/null +++ b/programs/media/Beat/PlayNote/PlayNote_lib1.h @@ -0,0 +1,97 @@ + +/* + * Author: JohnXenox aka Aleksandr Igorevich. + * + * PlayNote_lib1.h +*/ + +#ifndef __PlayNote_lib1_h__ +#define __PlayNote_lib1_h__ + +static inline int initMemory(void) +{ + int size; + + __asm__ __volatile__("int $0x40":"=a"(size):"a"(68),"b"(11)); + return size; +} + + +static inline void makeDelay(int time) +{ + __asm__ __volatile__("int $0x40"::"a"(5), "b"(time):"memory"); +} + + +static inline void *openFile(int *length, const char *path) +{ + int *fd; + + __asm__ __volatile__ ("int $0x40":"=a"(fd), "=d"(*length):"a" (68), "b"(27),"c"(path)); + + return fd; +} + + + +static inline void setCurrentPathToARawFile(char *dst_path, char *src_path, char* file_name) +{ + unsigned offset = 0; + + // cleans a dst path if not clean. + if(dst_path[offset] != 0) + { + for(; dst_path[offset] != 0; offset++) dst_path[offset] = 0; + } + + // copys current path into a buffer. + strcpy(dst_path, src_path); + + offset = 0; + + // go to the end of a string. + while(dst_path[offset] != 0) offset++; + + // clears all bytes to a character '/'. + for(; dst_path[offset] != '/'; offset--) dst_path[offset] = 0; + + // increments a variable. + offset++; + + // stores a name of a file in a buffer. + strcpy(dst_path + offset, file_name); +} + + + +void __attribute__ ((noinline)) printfOnADebugBoard(const char *format,...) +{ + va_list ap; + char log_board[300]; + + va_start (ap, format); + tiny_vsnprintf(log_board, sizeof log_board, format, ap); + va_end(ap); + + char *str = log_board; + + while(*str) __asm__ __volatile__("int $0x40"::"a"(63), "b"(1), "c"(*str++)); +} + + + + + + + + + + +#endif + + + + + + + diff --git a/programs/media/Beat/PlayNote/PlayNote_lib2.h b/programs/media/Beat/PlayNote/PlayNote_lib2.h new file mode 100644 index 0000000000..8134dcbb45 --- /dev/null +++ b/programs/media/Beat/PlayNote/PlayNote_lib2.h @@ -0,0 +1,246 @@ + +/* + * Author: JohnXenox aka Aleksandr Igorevich. + * + * PlayNote_lib2.h +*/ + +#ifndef __PlayNote_lib2_h__ +#define __PlayNote_lib2_h__ + +/* +struct CTRL_INFO +{ int pci_cmd; + int irq; + int glob_cntrl; + int glob_sta; + int codec_io_base; + int ctrl_io_base; + int codec_mem_base; + int ctrl_mem_base; + int codec_id; +}; +#define CTRL_INFO_SIZE (9*4) +*/ + +//====================================// + +#define SRV_GETVERSION 0 +#define SND_CREATE_BUFF 1 +#define SND_DESTROY_BUFF 2 +#define SND_SETFORMAT 3 +#define SND_GETFORMAT 4 +#define SND_RESET 5 +#define SND_SETPOS 6 +#define SND_GETPOS 7 +#define SND_SETBUFF 8 +#define SND_OUT 9 +#define SND_PLAY 10 +#define SND_STOP 11 +#define SND_SETVOLUME 12 +#define SND_GETVOLUME 13 +#define SND_SETPAN 14 +#define SND_GETPAN 15 +#define SND_GETBUFFSIZE 16 +#define SND_GETFREESPACE 17 +#define SND_SETTIMEBASE 18 +#define SND_GETTIMESTAMP 19 + + +#define DEV_SET_BUFF 4 +#define DEV_NOTIFY 5 +#define DEV_SET_MASTERVOL 6 +#define DEV_GET_MASTERVOL 7 +#define DEV_GET_INFO 8 + +//====================================// + +#define SOUND_VERSION 0x0101 +#define PCM_ALL 0 + +#define PCM_OUT 0x08000000 +#define PCM_RING 0x10000000 +#define PCM_STATIC 0x20000000 +#define PCM_FLOAT 0x40000000 +#define PCM_FILTER 0x80000000 + +#define PCM_2_16_48 1 +#define PCM_1_16_48 2 +#define PCM_2_16_44 3 +#define PCM_1_16_44 4 +#define PCM_2_16_32 5 +#define PCM_1_16_32 6 +#define PCM_2_16_24 7 +#define PCM_1_16_24 8 +#define PCM_2_16_22 9 +#define PCM_1_16_22 10 +#define PCM_2_16_16 11 +#define PCM_1_16_16 12 +#define PCM_2_16_12 13 +#define PCM_1_16_12 14 +#define PCM_2_16_11 15 +#define PCM_1_16_11 16 +#define PCM_2_16_8 17 +#define PCM_1_16_8 18 +#define PCM_2_8_48 19 +#define PCM_1_8_48 20 +#define PCM_2_8_44 21 +#define PCM_1_8_44 22 +#define PCM_2_8_32 23 +#define PCM_1_8_32 24 +#define PCM_2_8_24 25 +#define PCM_1_8_24 26 +#define PCM_2_8_22 27 +#define PCM_1_8_22 28 +#define PCM_2_8_16 29 +#define PCM_1_8_16 30 +#define PCM_2_8_12 31 +#define PCM_1_8_12 32 +#define PCM_2_8_11 33 +#define PCM_1_8_11 34 +#define PCM_2_8_8 35 +#define PCM_1_8_8 36 + +//====================================// + +const char szInfinity[] = "INFINITY"; +const char szSound[] = "SOUND"; + +int *hSound = 0; +int *hrdwSound = 0; + +struct MNG_DRV +{ + int *handle; + int code; + int **input; + int inp_size; + int **output; + int out_size; +}; + +static inline void *LoadDriver(void *ptr) +{ + void *val; + __asm__ __volatile__("int $0x40":"=a"(val):"a"(68), "b"(16),"c"(ptr)); + return val; +} + +static inline int ManageDriver(void *ptr) +{ + int val; + __asm__ __volatile__("int $0x40":"=a"(val):"a"(68), "b"(17),"c"(ptr)); + return val; +} + + + +static int _InitSound(int* p_ver) +{ + hSound = LoadDriver(&szInfinity); + if(hSound == 0) return -1; + hrdwSound = LoadDriver(&szSound); + + struct MNG_DRV MNG_DRV = { + .handle = hSound, + .code = SRV_GETVERSION, + .input = 0, + .inp_size = 0, + .output = &p_ver, + .out_size = 4 + }; + + return ManageDriver(&MNG_DRV); +} + + + +static int _CreateBuffer(int format, int size, int *p_str) +{ + struct MNG_DRV MNG_DRV = { + .handle = hSound, + .code = SND_CREATE_BUFF, + .input = &(int*)format, + .inp_size = 8, + .output = &p_str, + .out_size = 4 + }; + + return ManageDriver(&MNG_DRV); +} + + + +static int _SetBuffer(int *str, int* src, int offs, int size) +{ + struct MNG_DRV MNG_DRV = { + .handle = hSound, + .code = SND_SETBUFF, + .input = &(int*)str, + .inp_size = 16, + .output = 0, + .out_size = 0 + }; + + return ManageDriver(&MNG_DRV); +} + + + +static int _PlayBuffer(int* str, int flags) +{ + struct MNG_DRV MNG_DRV = { + .handle = hSound, + .code = SND_PLAY, + .input = &(int*)str, + .inp_size = 8, + .output = 0, + .out_size = 0 + }; + + return ManageDriver(&MNG_DRV); +} + + + +static int _SetBufferPos(int *str, int offs) +{ + struct MNG_DRV MNG_DRV = { + .handle = hSound, + .code = SND_SETPOS, + .input = &(int*)str, + .inp_size = 8, + .output = 0, + .out_size = 0 + }; + + return ManageDriver(&MNG_DRV); +} + + + +static int _StopBuffer(int* str) +{ + struct MNG_DRV MNG_DRV = { + .handle = hSound, + .code = SND_STOP, + .input = &(int*)str, + .inp_size = 4, + .output = 0, + .out_size = 0 + }; + + return ManageDriver(&MNG_DRV); +} + + + + + + + + + +#endif + + diff --git a/programs/media/Beat/PlayNote/Readme-en.txt b/programs/media/Beat/PlayNote/Readme-en.txt new file mode 100644 index 0000000000..d802f55f9e --- /dev/null +++ b/programs/media/Beat/PlayNote/Readme-en.txt @@ -0,0 +1,29 @@ +PlayNote (release date 2020.05.17) + +PlayNote is a programme to play a note. Sound plays through a sound driver. + +Usage: PlayNote + path - path to a file to be played. + +Examples: + PlayNote note.raw + PlayNote /tmp0/1/note.raw + +=========================== +To generate a note in a .wav format with a sox (to listening): + sox -n -L -c 1 -b 16 -r 48000 Note_C6.wav synth 1 sine 1046.4 +To generate a note in a .raw format with a sox (to PlayNote): + sox -n -L -c 1 -b 16 -r 48000 Note_C6.raw synth 1 sine 1046.4 + +To install a sox in Ubuntu: + sudo apt install sox +=========================== + +//--------------------------------------// + The programme: + - Compiled with KTCC compiler. + - Written in KolibriOS NB svn7768. + - Designed and written by JohnXenox + aka Aleksandr Igorevich. +//--------------------------------------// + diff --git a/programs/media/Beat/PlayNote/Readme-ru.txt b/programs/media/Beat/PlayNote/Readme-ru.txt new file mode 100644 index 0000000000..cf759353a1 --- /dev/null +++ b/programs/media/Beat/PlayNote/Readme-ru.txt @@ -0,0 +1,28 @@ +PlayNote (дата выпуска 2020.05.17) + +PlayNote - простая программа для проигрывания ноты. Звук проигрывается через звуковой драйвер. + +Использование: PlayNote + path - путь к файлу, который будет проигран. + +Примеры: + PlayNote note.raw + PlayNote /tmp0/1/note.raw + +=========================== +Для генерирования ноты в формате .wav при помощи sox (для прослушивания результата: + sox -n -L -c 1 -b 16 -r 48000 Note_C6.wav synth 1 sine 1046.4 +Для генерирования ноты в формате .raw при помощи sox (для программы PlayNote): + sox -n -L -c 1 -b 16 -r 48000 Note_C6.raw synth 1 sine 1046.4 + +Для установки программы sox в Ubuntu: + sudo apt install sox +=========================== + +//--------------------------------------// + The programme: + - Compiled with KTCC compiler. + - Written in KolibriOS NB svn7768. + - Designed and written by JohnXenox + aka Aleksandr Igorevich. +//--------------------------------------// diff --git a/programs/media/Beat/PlayNote/Test.zip b/programs/media/Beat/PlayNote/Test.zip new file mode 100644 index 0000000000..f9f4b3a594 Binary files /dev/null and b/programs/media/Beat/PlayNote/Test.zip differ diff --git a/programs/media/Beat/Readme-en.txt b/programs/media/Beat/Readme-en.txt new file mode 100644 index 0000000000..8333dca3f5 --- /dev/null +++ b/programs/media/Beat/Readme-en.txt @@ -0,0 +1,26 @@ +Beat (release date 2020.05.17) + +Beat is a simple metronome. Uses a PlayNote programme. +Samples Beep1.raw and Beep2.raw must be placed with a Beat. + +A PlayNote must be placed in one of the next directory: +/sys, /sys/media or in the same place as a Beat. + +Hot keys: +- CTRL + LEFT ARROW - backward tempo mnemonics. +- CTRL + LEFT ARROW - forward tempo mnemonics. +- LEFT ARROW - decreases a tempo beat (beats per minute). +- RIGHT ARROW - increases a tempo beat (beats per minute). +- COMMA - decreases a meter. +- DOT - increases a meter. +- SLASH - inverts colours of a counter indicator. +- From "NUM 1" to "+ SIGN") - (1 ... 12) makes an accent on selected beat. + +//--------------------------------------// + The programme: + - Compiled with KTCC compiler. + - Written in KolibriOS NB svn7768. + - Designed and written by JohnXenox + aka Aleksandr Igorevich. +//--------------------------------------// + diff --git a/programs/media/Beat/Readme-ru.txt b/programs/media/Beat/Readme-ru.txt new file mode 100644 index 0000000000..88ef557068 --- /dev/null +++ b/programs/media/Beat/Readme-ru.txt @@ -0,0 +1,26 @@ +Beat (дата выпуска 2020.05.17) + +Beat - простой метроном. Для работы использует программу PlayNote. +Сэмплы Beep1.raw и Beep2.raw должны находится с рядом программой Beat. + +Программа PlayNote должна находиться в одной из следующих директорий: +/sys, /sys/media или в томже месте, что и Beat. + +Горячие клавиши: +- CTRL + LEFT ARROW - перемотка обратно мнемоник темпа. +- CTRL + LEFT ARROW - премотка вперёд мнемоник темпа. +- LEFT ARROW - уменьшает бит темпа (биты в минуту). +- RIGHT ARROW - увеличивает бит темпа (биты в минуту). +- COMMA - уменьшает метр. +- DOT - увеличивает метр. +- SLASH - инвертирует цвета индикатора темпа. +- От "NUM 1" до "+ SIGN") - (1 ... 12) делает акцент на выбраном бите. + + +//--------------------------------------// + The programme: + - Compiled with KTCC compiler. + - Written in KolibriOS NB svn7768. + - Designed and written by JohnXenox + aka Aleksandr Igorevich. +//--------------------------------------//