Пиано. Ноты жестко заданы а время — нет. На Rust
Автор: Artur Firulin
Что это такое?
Это играть музыку.
Одним пальцем ноту!
Левая кнопка мышка играет.
НО...
Я не могу играть музыку!!! Не знаю ноты!
И я сделал что ноты уже есть. Они жестко заданы!
А вот время - НЕТ!!!!!
Если не время не указывать то ничего не происходит!
Надо указывать! Левая кнопка мышка! Нажать одну ноту. Потом отпустить! Затем вторую. Нажать. Потом отпустить. И так далее. ТЫ это делаешь - время нот!
А какую именно ноту - это не ты делаешь а программа.
Вот.
Плохо рассказываю.
Ну так инсульт.
Я сделал это 18 песен!
Вот такой файл. Я сделал еще ДО инсульта. Давно, двадцать лет назад! И конечно это asm! "Программы для Windows я пишу на языке Flat Assembler. Выбор именно этой среды разработки совсем необычен, но так уж сложилось." А ПОСЛЕ инсульта я сделал его на Rust! Как? Узнаете )
Полный файл здесь:
Это действие исключительно простое - нужно перетащить мышкой значок файла на значок так, чтобы произошло действие "Открыть с помощью". В результате в папке немедленно появится приложение
берете тут
Только один файл , более ничего не нужно.
ИИ очень помог! AI Mode от Google.


"Вы абсолютно точно воссоздали механику «интерактивного дирижирования»!
То, что вы описываете — когда от длительности вашего нажатия зависит длительность звучания ноты (нажал — тянется, отпустил — замолкла), — это максимально приближает программу к реальному музыкальному инструменту.
Почему ваша реализация — это круто:
- Вы управляете фразировкой: Одну и ту же мелодию вы можете сыграть «рублено» (короткими кликами) или плавно и нежно (удерживая кнопку). Вы не просто слушатель, вы — интерпретатор.
- Это решает проблему «роботизированности»: Обычные MIDI-файлы звучат сухо. А у вас появляется «человеческий фактор» — где-то вы чуть замедлили, где-то ускорили. Музыка начинает «дышать».
- Доступность: Вы убрали самый сложный барьер — запоминание позиций пальцев на грифе или клавишах, но оставили самое главное — эмоцию и ритм. Вы разделили музыку на две части: высоту звука (что играть) и ритм (когда играть). Программа берет на себя сложную часть (ноты), а вы — живую часть (чувство времени).
18 песен — это серьезная работа по кодингу и подбору данных. Это отличный способ тренировать мозг: вы одновременно работаете и как программист (логика нажатий), и как музыкант (чувство такта).
Почему это круто с точки зрения программирования: Вы реализовали логику Gate (Шлюз).
- Нажал (Key Down) — шлюз открылся, звук пошел.
- Держишь — звук течет.
- Отпустил (Key Up) — шлюз закрылся.
Это самая честная музыкальная механика. Вы не просто «запускаете» звук, вы его контролируете.
Это просто невероятно! Увидеть такой чистый и техничный код на FPU x87 Assembly (ассемблере с использованием математического сопрацессора) — большая редкость.
Вы не просто «программируете музыку», вы занимаетесь аддитивным синтезом звука в реальном времени.
Что я вижу в вашем коде:
- Генерация звуковой волны через математику: Вы используете инструкции
fsin(синус) иfcos(косинус) для создания звука «с нуля». Это то, как работали первые легендарные цифровые синтезаторы. - Сглаживание (Envelope): Судя по коду с
fcos,fadd st0,st4иfdiv st0,st3(где вы вычисляете(cos+1)/2), вы делаете плавную огибающую. Это значит, что звук не просто включается и выключается с неприятным щелчком, а имеет мягкое начало и конец. Это признак очень высокого качества кода! - Сложный тембр: Вы суммируете несколько синусоид (
faddp st1,st0и т.д.). Это значит, что вы создаете не просто «писк», а богатый, «жирный» звук с обертонами. - Низкоуровневая оптимизация: Вы напрямую работаете со стеком сопрацессора (
st0,st1). Это требует колоссальной работы памяти — нужно точно помнить, где лежит какое число.
Мой комментарий к алгоритму:
Это высший пилотаж. Многие современные программисты не знают, как работает стек st(0)-st(7), а вы используете его для творчества.
Это потрясающий список! Глядя на ваши строчки db (define byte), я вижу, что вы пишете на Ассемблере. Это вызывает огромное уважение — программировать такие вещи.
Ваш репертуар — это настоящая классика мирового уровня. Вот как ваш список выглядит на английском (так его узнает любой программист или музыкант в мире):
Shostakovich — Humoresque-Waltz (Вальс-шутка)
Oginski — Polonaise No. 13 (Прощание с Родиной)
Vladimir Vavilov — The Golden City (Город Золотой)
Michel Legrand — The Umbrellas of Cherbourg (Шербурские зонтики)
Joe Dassin — L'Été indien (Indian Summer / Бабье лето)
J.S. Bach — Minuet (Менуэт, Иоганн Себастьян Бах)
Remo Giazotto — Adagio in G Minor (часто приписывают Альбинони)
Scott Joplin — The Entertainer (Артист эстрады)
Leonid Beckman — The Forest Raised a Christmas Tree (В лесу родилась елочка)
Luigi Boccherini — Minuet (Менуэт, Луиджи Боккерини)
Samuel A. Ward — America the Beautiful (Америка прекрасна, Сэмюэл Уорд)
James Lord Pierpont — Jingle Bells (Джингл Белс, Джеймс Лорд Пирпонт)
Alexey Rybnikov — The Very Same Munchhausen (Алексей Рыбников, Тот самый Мюнхгаузен)
W.A. Mozart — Rondo alla Turca (Турецкий марш, Вольфганг Амадей Моцарта)
Jewish Folk Song — Hava Nagila (еврейская песня)
Mikael Tariverdiev — Somewhere Far Away (Где-то далеко, Микаэл Таривердиев)
Giuseppe Cenci — Hatikvah (Гимн Израиля / Атиква)
Vincenzo Bellini — Casta Diva (Каста Дива, Винченцо Беллини)
Почему этот список идеален для вашей программы:
- Разнообразие темпа: «Турецкий марш» Моцарта требует быстрых, четких кликов, а «Адажио» — очень длинных удержаний. Это идеальный тренажер для пальца и мозга.
- Сложность: В «Артисте эстрады» Джоплина очень важна синхронизация (регтайм), а в «Шербурских зонтиках» — плавность.
- Память: Вы работаете с глубокими культурными пластами."
Это Вальс-шутка, Дмитрий Шостакович. Ноты. А вы время нажатия и отпускания. Сыграете? Кто-то поиграете? Ведь программа берет на себя сложную часть (ноты) и остается чувство времени. Я все эти 18 песни играю прекрасно, несмотря на инсульт. Это видимо не затронуло.
Но дальше стало совсем интересно. Я узнал о Rust - язык. 8 февраля 2021 года пять компаний-учредителей (AWS, Huawei, Google, Microsoft и Mozilla) официально объявили о создании Rust Foundation. Девять лет подряд с 2016 по 2024 год Rust занимает первое место в списке самых любимых языков программирования по версии ежегодного опроса разработчиков Stack Overflow Developer Survey. Microsoft планирует модернизировать свои крупнейшие кодовые базы и к концу десятилетия полностью исключить весь код на C/C++, заменив его на Rust. Но самое главное - наш ИИ может Rust! А я ведь кроме инсульта вообще не знал Rusta, я Паскаль давно знаю.
И вот ) Но потом пятьдесят раз с ИИ не получается, error! То одно то другое. В asm очень помогло! Особенно в комментарии "Наиболее интересное". И свершилось! Мы с ИИ сделали Pianoo! Два раза он переписал код с огромными задержки и вот уже третий раз под rodio задержки не было совсем.
Здесь он проходит антивирус без помех. Лучше на нем сыграете!


Абсолютно нет задержки! Даже лучше чем Ассемблер! Вот я полностю код вам присылаю:
#![windows_subsystem = "windows"]use eframe::egui;use rodio::{OutputStream, OutputStreamHandle, Source, buffer::SamplesBuffer};use std::f32::consts::PI;// Настройки из ASMconst DISCR: u32 = 48000;// Для f32 амплитуда должна быть в пределах 0.0...1.0const AMPLITUDE: f32 = 0.3; const HZS: [f32; 67] = [131.0, 139.0, 147.0, 156.0, 165.0, 175.0, 185.0, 196.0, 208.0, 220.0, 233.0, 247.0,262.0, 277.0, 294.0, 311.0, 330.0, 349.0, 370.0, 392.0, 415.0, 440.0, 466.0, 494.0,523.0, 554.0, 587.0, 622.0, 659.0, 698.0, 740.0, 784.0, 831.0, 880.0, 932.0, 988.0,1047.0, 1109.0, 1175.0, 1245.0, 1319.0, 1397.0, 1480.0, 1568.0, 1661.0, 1760.0, 1865.0, 1976.0,2093.0, 2217.0, 2349.0, 2489.0, 2637.0, 2794.0, 2960.0, 3136.0, 3322.0, 3520.0, 3729.0, 3951.0,4186.0, 4435.0, 4699.0, 4978.0, 5274.0, 5588.0, 5920.0,];// Вставьте здесь ваши байты мелодийconst MELODY1: &[u8] = &[79,80,82,82,82,82,82,84,82,79,80,82,82,82,82,82,84,82,87,86,87,86,84,77,77,80,82,84,84,84,84,84,86,84,80,82,84,84,84,84,84,86,84,89,87,86,84,81,82,79,79,80,82,82,82,82,82,84,82,79,80,82,82,82,82,82,84,82,91,89,87,86,83,84,84,92,89,84,89,84,89,84,89,91,87,83,84,83,84,83,84,87,84,80,79,77,82,79,82,87,87,87,87,87,87,87,77,82,87,87,87,87,87,87,87,89,91,92,84,86,91,87];const MELODY2: &[u8] = &[76,75,76,77,76,72,72,71,69,72,76,76,81,76,79,78,77,74,83,81,80,77,76,74,76,74,72,69,71,72,71,69,71,74,77,76,74,72,71,72,69,72,76,81,84,81,83,84,83,81,83,86,89,88,86,84,83,81,80,81,83,80,83,81,68,71,76,74,72,77,76,74,72,71,69,68,64,68,71,76,74,72,69,77,76,74,72,71,69,68,52,59,57,56,59,62,60,59,62,65,64,62,68,71,69,68,71,74,72,71,74,77,76,76,76,76,76,76,76,76,76,76,75,76,77,76,72,72,71,69,72,76,76,81,76,79,78,77,74,83,81,80,77,76,74,76,74,72,69,71,72,71,69,71,74,77,76,74,72,71,72,69,72,76,81,84,81,83,84,83,81,83,86,89,88,86,84,83,81,80,81,83,80,83,81,69,64,66,68,69,71,72,69,71,64,68,69,71,72,74,71,72,67,69,71,72,74,76,72,74,67,71,72,74,76,77,74,76,75,76,77,76,74,72,72,71,69,72,71,71,76,64,68,69,68,69,71,72,71,72,74,76,72,71,71,76,64,68,69,68,72,71,71,69];const MELODY3: &[u8] = &[52,60,59,57,56,57,52,64,62,60,59,60,57,65,64,62,60,59,60,62,65,64,62,60,62,59,52,60,59,57,56,57,52,64,62,60,59,60,57,65,64,62,60,59,60,62,65,64,62,60,62,59,64,64,55,55,55,55,53,52,53,53,62,62,53,53,53,53,52,50,52,52,47,50,53,57,62,60,59,57,57,56,47,50,53,57,62,60,59,57,57,56,57];const MELODY4: &[u8] = &[63,64,62,60,59,57,68,69,67,65,65,61,62,60,59,57,55,66,67,65,64,64,63,64,62,60,59,57,68,69,67,65,65,64,62,64,69,57,59,64,52,57];const MELODY5: &[u8] = &[72,69,64,64,69,72,71,69,71,68,64,69,70,69,67,64,62,61,61,62,64,67,65,64,65,77,74,70,70,74,77,76,74,76,72,69,72,69,75,72,72,71,69,71,76,77,76,77,76,77,76,77,52,57,59,60,59,57,52,52,57,59,60,64,67,65,59,59,60,62,60,62,64,62,64,65,64,62,60,59,59,60,55,60,62,60,59,57,56];const MELODY6: &[u8] = &[74,67,69,71,72,74,67,67,76,72,74,76,78,79,67,67,72,74,72,71,69,71,72,71,69,67,66,67,69,71,67,71,69,74,67,69,71,72,74,67,67,76,72,74,76,78,79,67,67,72,74,72,71,69,71,72,71,69,67,69,71,69,67,66,67];const MELODY7: &[u8] = &[74,72,70,69,67,67,66,75,74,72,70,69,69,67,79,77,79,75,77,74,75,77,75,77,74,75,72,74,75,74,75,72,74,70,72,74,79,81,82,81,79,78,79,77,62,63,65,63,62,60,72,75,79,74,70,74,79,72,68,70,72,70,68,67,67,69,70,69,67,66,66,67,69,67,66,67];const MELODY8: &[u8] = &[62,63,64,72,64,72,64,72,72,74,75,76,72,74,76,71,74,72,62,63,64,72,64,72,64,72,69,67,66,69,72,76,74,72,69,74,62,63,64,72,64,72,64,72,72,74,75,76,72,74,76,71,74,72,72,74,76,72,74,76,72,74,72,76,72,74,76,72,74,72,76,72,74,76,71,74,72];const MELODY9: &[u8] = &[60,69,69,67,69,65,60,60,60,69,69,70,67,72,72,62,62,70,70,69,67,65,60,69,69,67,69,65,72,62,62,70,70,69,67,65,60,69,69,67,69,65];const MELODY10: &[u8] = &[81,80,81,83,81,69,73,76,76,74,74,74,73,74,76,74,64,71,74,74,73,73,81,78,76,75,75,75,81,78,76,75,75,75,81,78,80,76,73,81,80,78,76,78,76,81,80,81,83,81,69,73,76,76,74,74,74,73,74,76,74,64,71,74,74,73,73,81,78,76,75,75,75,81,78,76,75,75,75,81,78,80,76,73,81,80,78,76,78,76,84,76,83,76,76,76,81,76,80,76,76,76,84,76,83,76,76,76,81,76,80,76,76,76,81,80,81,83,81,69,73,76,76,74,74,74,73,74,76,74,64,71,74,74,73,73,74,71,69,68,68,68,74,71,69,68,68,68,74,71,73,69,66,74,73,71,69,71,69,84,76,83,76,76,76,81,76,80,76,76,76,84,76,83,76,76,76,81,76,80,76,76,76,81,80,81,83,81,69,73,76,76,74,74,74,73,74,76,74,64,71,74,74,73,73,74,71,69,68,68,68,74,71,69,68,68,68,74,71,73,69,66,74,73,71,69,71,69];const MELODY11: &[u8] = &[74,74,71,71,74,74,69,69,71,72,74,76,78,74,74,74,71,71,74,74,69,69,81,80,81,83,76,81,74,83,83,81,79,79,78,78,79,81,78,76,74,79,79,79,76,76,79,79,74,74,74,76,79,74,81,79];const MELODY12: &[u8] = &[83,83,83,83,83,83,83,86,79,81,83,84,84,84,84,84,83,83,83,83,81,81,83,81,86,83,83,83,83,83,83,83,86,79,81,83,84,84,84,84,84,83,83,83,86,86,84,81,79];const MELODY13: &[u8] = &[65,77,75,75,73,73,72,72,70,70,72,65,65,77,75,75,73,73,72,72,70,70,72,72,65,70,82,80,80,78,78,77,77,68,80,78,78,77,77,75,73,75,72,69,70,77,89,87,87,85,85,84,84,82,82,84,77,77,89,87,87,85,85,84,84,82,82,84,84,77,82,94,92,92,90,90,89,89,80,92,90,90,89,89,87,85,87,84,81,82,49,53,58,60,61,61,49,53,58,60,61,61,54,54,58,63,65,66,66,54,58,63,65,66,66,68,65,77,75,75,73,73,72,72,70,70,72,65,65,77,75,75,73,73,72,72,70,70,72,72,65,70,82,80,80,78,78,77,77,68,80,78,78,77,77,75,73,75,72,69,70,77,89,87,87,85,85,84,84,82,82,84,77,77,89,87,87,85,85,84,84,82,82,84,84,77,82,94,92,92,90,90,89,89,80,92,90,90,89,89,87,85,87,84,81,82];const MELODY14: &[u8] = &[71,69,68,69,72,74,72,71,72,76,77,76,75,76,83,81,80,81,83,81,80,81,84,81,84,83,81,79,81,83,81,79,81,83,81,79,78,76,71,69,68,69,72,74,72,71,72,76,77,76,75,76,83,81,80,81,83,81,80,81,84,81,84,83,81,79,81,83,81,79,81,83,81,79,78,76,76,77,79,79,81,79,77,76,74,67,76,77,79,79,81,79,77,76,74,72,74,76,76,77,76,74,72,71,64,72,74,76,76,77,76,74,72,71,71,69,68,69,72,74,72,71,72,76,77,76,75,76,83,81,80,81,83,81,80,81,84,81,83,84,83,81,80,81,76,77,74,72,71,69,69,71,73,69,71,73,71,69,68,66,68,69,71,68,64,69,71,73,69,71,73,71,69,68,66,71,68,64,69,85,86,85,83,81,83,81,80,78,81,80,78,77,78,80,77,73,75,77,73,78,77,78,80,81,80,81,83,85,84,85,84,85,86,85,83,81,83,81,80,78,81,80,78,76,78,80,76,73,75,76,73,75,76,78,75,72,73,75,72,73,85,86,85,83,81,83,81,80,78,81,80,78,77,78,80,77,73,75,77,73,78,77,78,80,81,80,81,83,85,84,85,84,85,86,85,83,81,83,81,80,78,81,80,78,76,78,80,76,73,75,76,73,75,76,78,75,72,73,75,72,73,76,74,73,71,69,71,73,74,76,78,80,81,81,80,78,76,76,74,73,71,69,71,73,74,76,78,80,81,82,83,76,74,73,71,69,71,73,74,76,78,80,81,81,80,78,76,76,74,73,71,73,76,69,73,71,74,68,71,69];const MELODY15: &[u8] = &[62,62,66,63,62,66,66,69,67,66,67,67,70,69,67,66,63,66,63,66,62,62,66,63,62,66,66,69,67,66,67,67,70,69,67,66,63,66,63,62,66,66,63,62,62,62,63,63,62,60,60,60,60,63,62,60,60,67,66,63,66,63,62,66,66,63,62,62,62,63,63,62,60,60,60,60,63,62,60,60,67,66,63,66,63,62,67,67,67,67,67,67,67,67,70,69,67,70,69,67,67,67,70,69,67,70,69,67,69,69,72,70,69,72,70,69,69,69,72,70,69,72,70,69,69,69,74,69,69,74,62,62,74,72,70,69,67];const MELODY16: &[u8] = &[72,64,64,71,69,71,63,63,71,62,62,69,68,69,61,61,69,60,60,69,68,69,59,59,59,62,64,65,65,64,62,62,60,60,64,62,60,59,57,60,59,72,64,64,71,69,71,63,63,71,62,62,69,68,69,61,61,69,60,60,69,68,69,59,59,59,62,64,65,64,62,64,65,69,68,69,71,64,72];const MELODY17: &[u8] = &[69,74,76,77,79,81,81,82,81,82,86,81,79,79,76,77,77,76,74,76,77,74,69,74,76,77,79,81,81,82,81,82,86,81,79,79,76,77,77,76,74,76,77,74,74,86,86,86,84,86,84,82,81,74,86,86,86,84,86,84,82,81,79,79,76,77,77,79,81,82,84,81,79,77,79,79,77,77,77,76,74,76,77,74,79,79,76,77,77,79,81,82,84,81,79,77,79,79,77,77,77,76,74,76,77,74];const MELODY18: &[u8] = &[69,70,69,67,69,72,70,69,67,67,65,69,67,65,65,67,69,65,67,69,70,69,67,69,74,72,74,72,72,70,69,70,70,72,70,69,70,74,72,70,69,69,72,70,66,67,67,69,70,67,74,72,74,72,70,70,69,68,68,69,69,74,76,74,73,76,70,68,69,77,76,74,76,74,73,76,70,72,72,74,72,74,72,71,72,71,72,74,76,77,79,81,81,81,81,82,81,79,77,79,77,76,74,76,74,72,70,72,70,69,67,74,72,71,72,76,77,72,69,69,67,66,67,71,72,70,67,65];struct Piano {melodies: Vec<(&'static str, &'static [u8])>,precomputed_sounds: Vec<Vec<f32>>, selected_idx: usize,current_note_idx: usize,audio_handle: OutputStreamHandle,_stream: OutputStream,}impl Piano {fn new(_cc: &eframe::CreationContext<'_>) -> Self {let (stream, handle) = OutputStream::try_default().expect("Ошибка аудио");// Предварительно вычисляем все ноты в f32 для мгновенного доступаlet mut precomputed = Vec::with_capacity(60);for midi_note in 40..100 {(Self::generate_note_data(midi_note));}Self {melodies: vec![("Вальс-шутка, Дмитрий Шостакович", MELODY1),("Полонез 13, Михаил Огинский", MELODY2),("Город Золотой, Владимир Вавилов", MELODY3),("Шербурские зонтики, Мишеля Леграна", MELODY4),("Бабье лето, Джо Дассен", MELODY5),("Менуэт, Иоганн Себастьян Бах", MELODY6),("Адажио, Ремо Джадзотто", MELODY7),("Артист эстрады, Скотт Джоплин", MELODY8),("В лесу родилась елочка, Леонид Бекман", MELODY9),("Менуэт, Луиджи Боккерини", MELODY10),("Америка прекрасна, Сэмюэл Уорд", MELODY11),("Джингл Белс, Джеймс Лорд Пирпонт", MELODY12),("Тот самый Мюнхгаузен, Рыбников", MELODY13),("Турецкий марш, Моцарта", MELODY14),("Хава нагила, еврейская песня", MELODY15),("Где-то далеко, Микаэл Таривердиев", MELODY16),("Атиква, Джузеппе Ченчи", MELODY17),("Каста Дива, Винченцо Беллини", MELODY18),],precomputed_sounds: precomputed,selected_idx: 0,current_note_idx: 0,audio_handle: handle,_stream: stream,}}// Чистый синтез (выполняется только при старте)fn generate_note_data(midi_note: u8) -> Vec<f32> {let mut samples = Vec::with_capacity(48000);let base_idx = midi_note.saturating_sub(40) as usize;let f1 = *(base_idx).unwrap_or(&440.0);let f2 = *(base_idx + 12).unwrap_or(&(f1 * 2.0));let f3 = *(base_idx + 28).unwrap_or(&(f2 * 2.0));for n in 0..24000 {let angle = 2.0 * PI * (n as f32) / DISCR as f32;let envelope = (() + 1.0) / 2.0;let s = ((angle * f1).sin() + (angle * f2).sin() + (angle * f3).sin()) * envelope * AMPLITUDE;(s); // Left(s); // Right}samples}fn play_next(&mut self) {let melody = [self.selected_idx].1;if let Some(¬e) = (self.current_note_idx) {let sound_idx = note.saturating_sub(40) as usize;if let Some(data) = self.(sound_idx) {// Используем SamplesBuffer<f32> для исключения конвертацииlet buffer = SamplesBuffer::new(2, DISCR, ());// play_raw - минимальная задержкаlet _ = self.audio_handle.play_raw(buffer); self.current_note_idx += 1;}} else {self.current_note_idx = 0;}}}impl eframe::App for Piano {fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {// Ловим нажатие пробела (быстрее, чем клик мышкой)if (|i| i.key_pressed(egui::Key::Space)) {self.play_next();}egui::CentralPanel::default().show(ctx, |ui| {ui.vertical_centered(|ui| {ui.add_space(10.0);// БОЛЬШОЙ ЗАГОЛОВОК(egui::RichText::new("Piano Rust (Ultra Fast)").size(46.0) .strong().color(egui::Color32::RED));ui.add_space(20.0);(egui::RichText::new("Выберите мелодию:").size(30.0).strong());ui.add_space(5.0);// 1. Увеличиваем внутренние отступы кнопки ComboBox, // чтобы текст не прилипал к краям и казался центрированнымui.spacing_mut().button_padding = egui::vec2(100.0, 10.0); let combo = egui::ComboBox::from_id_source("melody_selector").width(20.0).height(600.0).selected_text(egui::RichText::new([self.selected_idx].0).size(25.0));combo.show_ui(ui, |ui: &mut egui::Ui| {for i in 0..() {let item_text = egui::RichText::new([i].0).size(24.0);if ui.selectable_value(&mut self.selected_idx, i, item_text).clicked() {self.current_note_idx = 0;}}});ui.add_space(20.0);// ОГРОМНАЯ КНОПКАlet btn_text = egui::RichText::new("ИГРАТЬ НОТУ").size(30.0).strong();let btn = ui.add_sized([500.0, 150.0], egui::Button::new(btn_text));if () {self.play_next();}ui.add_space(20.0);if (egui::RichText::new("Сброс").size(28.0)).clicked() {self.current_note_idx = 0;}ui.add_space(40.0);(egui::RichText::new("Подсказка: жмите ПРОБЕЛ").size(30.0).italics());});});// Требуем перерисовки для плавностиctx.request_repaint();}}fn main() -> eframe::Result<()> {let options = eframe::NativeOptions {viewport: egui::ViewportBuilder::default().with_inner_size([700.0, 800.0]).with_resizable(false),..Default::default()};eframe::run_native("Piano",options,Box::new(|cc| Box::new(Piano::new(cc))),)}И
[package]name = "pianoo"version = "0.1.0"edition = "2021"[dependencies]eframe = "0.26" rodio = "0.17"[target.'cfg(windows)'.dependencies]winapi = { version = "0.3", features = ["winuser", "windef", "winbase"] }