From 8395783986fc1453d7f2543aaa931a53385203e9 Mon Sep 17 00:00:00 2001 From: JotaChina Date: Fri, 29 Aug 2025 16:38:40 -0300 Subject: [PATCH] MMPCreator --- _data/src_audio_files.json | 242 ------- _includes/sidebar.html | 3 +- _includes/sidebar_home.html | 1 + _layouts/projetos.html | 4 +- assets/css/sidebar.css | 3 +- assets/css/sidebar_home.css | 63 +- assets/css/style.css | 703 +++++++++++++++++++++ assets/js/creations/audio.js | 134 ++++ assets/js/creations/config.js | 9 + assets/js/creations/file.js | 243 +++++++ assets/js/creations/main.js | 121 ++++ assets/js/creations/state.js | 90 +++ assets/js/creations/ui.js | 319 ++++++++++ assets/js/creations/utils.js | 27 + assets/js/search.js | 111 ++-- automation.html | 134 ++-- bassline.html | 139 ++-- creation.html | 201 ++++++ scripts/creation/generateManifest.py | 101 +++ scripts/handler/automations/automations.py | 4 +- src/dtd/mmp.md | 179 ++++++ src/dtd/mmp.xsd | 512 +++++++++++++++ 22 files changed, 2883 insertions(+), 460 deletions(-) delete mode 100644 _data/src_audio_files.json create mode 100644 assets/css/style.css create mode 100644 assets/js/creations/audio.js create mode 100644 assets/js/creations/config.js create mode 100644 assets/js/creations/file.js create mode 100644 assets/js/creations/main.js create mode 100644 assets/js/creations/state.js create mode 100644 assets/js/creations/ui.js create mode 100644 assets/js/creations/utils.js create mode 100644 creation.html create mode 100644 scripts/creation/generateManifest.py create mode 100644 src/dtd/mmp.md create mode 100644 src/dtd/mmp.xsd diff --git a/_data/src_audio_files.json b/_data/src_audio_files.json deleted file mode 100644 index b95ea39..0000000 --- a/_data/src_audio_files.json +++ /dev/null @@ -1,242 +0,0 @@ -[ - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/effects/stop01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/effects/start01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/effects/warp01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/effects/wind_chimes01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/effects/start02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/effects/explode01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/effects/scratch01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/effects/filter_sweep01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/effects/chroma_sound_effect01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/effects/warp02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/applause01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/undefined01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/bass!.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/snaph01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/breath01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/hit02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/metronome01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/electric_ping01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/hit01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/metronome02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/dong03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/metalish_dong01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/dong02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/buzz!.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/raving_crowd01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/misc/dong01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/beats/break03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/beats/rave_snare01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/beats/jungle01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/beats/electro_beat01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/beats/rave_kick02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/beats/909beat01.ogg", - "mmp/instruments/lmms/samples/beats/rave_kick01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/beats/house_loop01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/beats/rave_hihat01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/beats/break02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/beats/rave_hihat02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/beats/break01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/beats/electro_beat02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/rave_bass04.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/matrix1000_pluck01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/rave_bass03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/bass_acid01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/techno_synth01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/bass01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/synth_acid02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/bass_hard01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/horror_bass01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/bass_acid02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/rave_bass02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/synth_acid01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/bass_punch01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/rave_bass01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/basses/bass_hard02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/stringsnpads/chorus02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/stringsnpads/bell_choir01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/stringsnpads/strings01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/stringsnpads/space_strings01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/stringsnpads/space_strings03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/stringsnpads/nord_ambient01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/stringsnpads/orion_string01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/stringsnpads/heaven_strings01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/stringsnpads/korg_poly6_drone01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/stringsnpads/bell_choir02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/stringsnpads/rave_choir01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/stringsnpads/space_strings02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/stringsnpads/juno_pad01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/stringsnpads/chorus01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/bunglist7.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/technobass.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/moog.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/smooth_inv_saw_dist.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/vowel_a.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/roundsaw.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/additive2.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/smooth_inv_saw.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/bunglist9.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/technosynth1.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/technosynth5.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/harmonics.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/smooth_inv_saw2.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/bunglist2.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/bunglist5.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/sine_dist.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/technosynth3.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/micro.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/bunglist.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/technosynth6.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/technosynth2.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/bunglist6.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/bunglist3.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/low_sine.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/saw+sine.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/bunglist4.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/additive.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/bunglist8.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/vowel_u.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/roundbass.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/shapes/technosynth4.wav", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/lfo_trancegate_quarter.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/modsqr.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/lfo_trancegate_triplet_quarter.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/w2_invsine.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/w2_invsinehalf.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/w2_addsyn.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/w2_sharp.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/lfo_trancegate_triplet_half_2.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/saw1.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/w2_rad.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/w2_sawsine.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/lfo_trancegate_sawdecay_quarter.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/w2_noisy.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/w2_hexagon.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/saw2.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/analogsqr.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/w2_invsineabs.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/lfo_trancegate_triplet_half.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/sinesaw.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/fmsaw1.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/lfo_trancegate_sinedecay_quarter.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/10saw.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/fmsine2.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/10tri.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/lfo_trancegate_whole_2.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/10sine.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/w2_angrysaw.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/w2_w-wave.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/10sqr.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/halfsine.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/fmsine.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/impulse.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/waveforms/lfo_trancegate_whole.flac", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/bassloops/techno_synth04.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/bassloops/tb303_01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/bassloops/techno_synth01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/bassloops/techno_synth02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/bassloops/techno_bass01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/bassloops/techno_synth03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/bassloops/rave_bass02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/bassloops/briff01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/bassloops/rave_bass01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/bassloops/techno_bass02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/latin/latin_brass01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/latin/latin_guitar03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/latin/latin_guitar02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/latin/latin_guitar01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/hihat_opened03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/kick_long01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/clap02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/kick03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/kick_hardcore01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/hihat_opened02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare_muffled02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/kick01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/nasty_bass01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/hihat_closed05.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/tom03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/tom05.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/kick_hiphop01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/clav02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/nasty_snare01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare_hiphop02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/tom02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare_hiphop01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/clap01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/zap03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/bassdrum_acoustic02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/tom_low01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare_short01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/bassdrum03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/bassdrum04.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/bassdrum01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare_harsh01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/shaker03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/tom_mid01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare_muffled01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare_electro01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/crash02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/sidestick01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/hihat_closed03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare_acoustic01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/hihat_closed01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/kick02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/shaker02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/nasty_rim01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/wood01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/crash01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/hihat_opened01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/ride02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/ride01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare04.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/tom01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/bassdrum02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/zap02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare06.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/zap01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/rim01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/hihat_foot_pedal01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/clav01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/clap04.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/kick_soft02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare07.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/clap03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/kick_hard01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare_rim01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/shaker01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/hihat_closed04.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/snare05.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/bassdrum_acoustic01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/kick_soft01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/kick04.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/tom04.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/hihat_closed02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/kick_distorted01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/drums/tom_hi01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/flute01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/e_organ01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/trumpet01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/violin_fingered01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/e_piano_accord02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/steel_guitar_heavy_distorted01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/church_organ04.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/steel_guitar_medium_distorted01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/violin_double_stop01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/steel_guitar_slight_distorted01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/church_organ01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/violin_pizzicato01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/bassslap01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/harpsichord01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/piano02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/church_organ03.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/cello01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/bassslap02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/church_organ02.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/e_piano_accord01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/piano01.ogg", - "/nethome/jotachina/projetos/mmpSearch/mmp/instruments/lmms/samples/instruments/steel_guitar01.ogg" -] \ No newline at end of file diff --git a/_includes/sidebar.html b/_includes/sidebar.html index c7ea55f..a15e2ef 100644 --- a/_includes/sidebar.html +++ b/_includes/sidebar.html @@ -7,7 +7,8 @@ 📁 Projetos por tipo de track 🎧 Beats Disponíveis 🎼 Projetos - 🔎 Buscas + 🔎 Buscas´ + 🧠 Crie seu projeto ℹ️ Sobre diff --git a/_includes/sidebar_home.html b/_includes/sidebar_home.html index 39682e5..bdda058 100644 --- a/_includes/sidebar_home.html +++ b/_includes/sidebar_home.html @@ -7,6 +7,7 @@ 🎧 Beats Disponíveis 🎼 Projetos Disponíveis 🔎 Buscas + 🧠 Crie seu projeto ℹ️ Sobre diff --git a/_layouts/projetos.html b/_layouts/projetos.html index f86a443..a40af5f 100644 --- a/_layouts/projetos.html +++ b/_layouts/projetos.html @@ -119,8 +119,8 @@ title: "{{ page.file }}"
diff --git a/assets/css/sidebar.css b/assets/css/sidebar.css index 8eb4d39..67d7608 100644 --- a/assets/css/sidebar.css +++ b/assets/css/sidebar.css @@ -6,7 +6,7 @@ background-color: #f4f4f4; padding: 1rem; border-radius: 8px; - box-shadow: 0 2px 5px rgba(0,0,0,0.1); + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); max-width: 100%; box-sizing: border-box; } @@ -40,4 +40,3 @@ padding: 0.3rem 0.6rem; } } - diff --git a/assets/css/sidebar_home.css b/assets/css/sidebar_home.css index e7f1d90..19de719 100644 --- a/assets/css/sidebar_home.css +++ b/assets/css/sidebar_home.css @@ -1,33 +1,32 @@ .sidebar-center { - position: fixed; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: #f4f4f4; - padding: 2rem 1.5rem; - border-radius: 12px; - box-shadow: 0 0 10px rgba(0,0,0,0.1); - z-index: 1000; - } - - .submenu { - display: flex; - flex-direction: column; - gap: 1rem; - align-items: center; - } - - .submenu a { - text-decoration: none; - color: #333; - font-weight: 500; - padding: 0.5rem 1rem; - border-radius: 6px; - transition: background 0.2s; - white-space: nowrap; - } - - .submenu a:hover { - background-color: #e0e0e0; - } - \ No newline at end of file + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: #f4f4f4; + padding: 2rem 1.5rem; + border-radius: 12px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + z-index: 1000; +} + +.submenu { + display: flex; + flex-direction: column; + gap: 1rem; + align-items: center; +} + +.submenu a { + text-decoration: none; + color: #333; + font-weight: 500; + padding: 0.5rem 1rem; + border-radius: 6px; + transition: background 0.2s; + white-space: nowrap; +} + +.submenu a:hover { + background-color: #e0e0e0; +} diff --git a/assets/css/style.css b/assets/css/style.css new file mode 100644 index 0000000..f261937 --- /dev/null +++ b/assets/css/style.css @@ -0,0 +1,703 @@ +/* =============================================== */ +/* VÁRIAVEIS GLOBAIS (ROOT) +/* =============================================== */ +:root { + --bg-body: #2d3035; + --bg-toolbar: #3b3f45; + --bg-editor: #33373d; + --border-color: #232529; + --text-light: #c0c0c0; + --text-dark: #888; + --accent-green: #2ecc71; + --accent-red: #d9534f; +} + +/* =============================================== */ +/* ESTILOS GLOBAIS E LAYOUT PRINCIPAL +/* =============================================== */ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + background-color: var(--bg-body); + color: var(--text-light); + padding-left: 300px; + transition: padding-left .3s ease; +} + +body.sidebar-hidden { + padding-left: 0; +} + +body.knob-dragging { + cursor: ns-resize; +} + +.main-content { + padding: 2rem; +} + +/* =============================================== */ +/* BARRA LATERAL (SAMPLE BROWSER) +/* =============================================== */ +.sample-browser { + position: fixed; + top: 0; + left: 0; + width: 300px; + height: 100vh; + background-color: var(--bg-toolbar); + border-right: 2px solid var(--border-color); + z-index: 1500; + display: flex; + flex-direction: column; + transform: translateX(0); + transition: transform .3s ease; +} + +body.sidebar-hidden .sample-browser { + transform: translateX(-100%); +} + +.browser-header { + padding: 15px; + background-color: #2a2c30; + border-bottom: 2px solid var(--border-color); + text-align: center; + font-weight: bold; + color: var(--text-light); +} + +.browser-content { + flex-grow: 1; + overflow-y: auto; + padding: 10px; +} + +.browser-content ul { + list-style: none; + padding-left: 15px; +} + +.browser-content li { + padding: 5px; + cursor: pointer; + border-radius: 3px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + user-select: none; +} + +.browser-content li:hover { + background-color: var(--bg-editor); +} + +.browser-content li i { + margin-right: 8px; + width: 12px; + color: var(--text-dark); + transition: transform .2s; +} + +.browser-content li.directory > ul { + display: none; +} + +.browser-content li.directory.open > ul { + display: block; +} + +.browser-content li.directory.open > .fa-folder { + transform: rotate(90deg); +} + +#sidebar-toggle { + position: fixed; + top: 60px; + left: 305px; + z-index: 1400; + background-color: var(--bg-toolbar); + border: 1px solid var(--border-color); + color: var(--text-light); + width: 25px; + height: 40px; + cursor: pointer; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + transition: left .3s ease; + display: flex; + align-items: center; + justify-content: center; +} + +body.sidebar-hidden #sidebar-toggle { + left: 5px; +} + +/* =============================================== */ +/* BARRA DE FERRAMENTAS GLOBAL +/* =============================================== */ +.global-toolbar { + padding: 8px 15px; + position: fixed; + top: 0; + /* Removido width 100% para se adaptar ao padding do body */ + left: 300px; + right: 0; + z-index: 1000; + display: flex; + align-items: center; + gap: 20px; + background-color: var(--bg-toolbar); + border-bottom: 2px solid var(--border-color); + transition: left .3s ease; +} + +body.sidebar-hidden .global-toolbar { + left: 0; +} + + +/* =============================================== */ +/* EDITOR DE BATIDAS (BEAT EDITOR) +/* =============================================== */ +.beat-editor { + background-color: var(--bg-body); + border: 1px solid var(--border-color); + width: 100%; + max-width: 900px; + margin: auto; + box-shadow: 0 5px 15px rgba(0, 0, 0, .3); + border-radius: 4px; + overflow: hidden; +} + +.editor-header { + background-color: var(--bg-toolbar); + padding: 4px 10px; + font-size: .8rem; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid var(--border-color); +} + +.window-controls i { + margin-left: 12px; + cursor: pointer; +} + +.editor-toolbar { + background-color: var(--bg-toolbar); + padding: 5px 10px; + display: flex; + align-items: center; + gap: 15px; + border-bottom: 2px solid var(--border-color); +} + +.editor-toolbar i { + cursor: pointer; + padding: 5px; + border-radius: 3px; +} + +.editor-toolbar i.enabled { + background-color: var(--bg-body); + box-shadow: inset 0 0 2px #000; +} + +.pattern-selector { + background-color: var(--bg-body); + padding: 5px 15px; + border: 1px solid var(--border-color); + flex-grow: 1; + font-size: .9rem; + border-radius: 2px; +} + +/* =============================================== */ +/* FAIXAS (TRACK LANES) E SEQUENCIADOR +/* =============================================== */ +.track-lane { + display: flex; + align-items: center; + padding: 8px 10px; + background-color: var(--bg-editor); + border: 2px dashed transparent; + transition: border-color 0.2s; +} + +.track-lane.drag-over { + border-color: var(--accent-green); +} + +.track-info { + display: flex; + align-items: center; + gap: 8px; + width: 180px; + flex-shrink: 0; +} + +.track-info .fa-gear { + font-size: 1.2rem; + cursor: pointer; +} + +.track-mute { + width: 25px; + height: 12px; + background-color: var(--accent-green); + border-radius: 6px; + cursor: pointer; + border: 1px solid var(--border-color); + box-shadow: inset 0 0 2px #000; +} + +.track-name { + color: var(--accent-red); + font-weight: 700; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.track-controls { + display: flex; + gap: 5px; + margin: 0 10px; + padding-left: 10px; + border-left: 1px solid var(--bg-toolbar); +} + +.knob-container { + text-align: center; + font-size: .7rem; + color: var(--text-dark); +} + +.knob { + width: 28px; + height: 28px; + background-color: var(--bg-toolbar); + border-radius: 50%; + border: 1px solid var(--border-color); + margin-bottom: 2px; + cursor: grab; + box-shadow: inset 0 0 4px #222; + position: relative; +} + +.knob:active { + cursor: grabbing; +} + +.knob-indicator { + width: 2px; + height: 8px; + background-color: var(--text-light); + position: absolute; + top: 2px; + left: 50%; + transform-origin: bottom center; + transform: translateX(-50%) rotate(0deg); + border-radius: 1px; +} + +.step-sequencer { + display: flex; + flex-grow: 1; + gap: 4px; + overflow-x: auto; + padding-bottom: 8px; +} + +.step-sequencer::-webkit-scrollbar { + height: 8px; +} + +.step-sequencer::-webkit-scrollbar-track { + background: var(--border-color); + border-radius: 4px; +} + +.step-sequencer::-webkit-scrollbar-thumb { + background: var(--bg-toolbar); + border-radius: 4px; +} + +.step-sequencer::-webkit-scrollbar-thumb:hover { + background: #555; +} + +.step-wrapper { + position: relative; +} + +.step-marker { + position: absolute; + top: -16px; + left: 1px; + font-size: .6rem; + color: var(--text-dark); +} + +.step { + width: 28px; + aspect-ratio: 1 / 1; + background-color: #2a2a2a; + border: 1px solid #4a4a4a; + border-radius: 2px; + cursor: pointer; + transition: background-color .1s, transform 0.1s; + flex-shrink: 0; /* Impede que os steps encolham */ +} + +.step-dark { + background-color: #1e1e1e; +} + +.step:hover { + background-color: #555; + border-color: #888; +} + +.step.active { + background-color: var(--accent-green); + border: 1px solid #fff; + box-shadow: 0 0 8px var(--accent-green); +} + +.step.playing { + transform: scale(1.1); + box-shadow: inset 0 0 8px rgba(255, 255, 255, 0.8); +} + +/* =============================================== */ +/* CONTROLES E INPUTS +/* =============================================== */ +.interactive-input-container { + display: flex; + align-items: center; + justify-content: center; + gap: 4px; +} + +.compasso-group { + display: flex; + align-items: center; + gap: 4px; +} + +.value-input { + background: 0 0; + border: 0; + outline: 0; + color: var(--accent-green); + font-weight: 700; + font-size: 1.4rem; + font-family: Courier New, Courier, monospace; + text-align: center; + padding: 0; + width: 55px; +} + +.compasso-input { + width: 25px; +} + +.compasso-separator { + color: var(--accent-green); + font-weight: 700; + font-size: 1.4rem; + font-family: Courier New, Courier, monospace; + margin: 0 2px; +} + +.value-input::-webkit-outer-spin-button, +.value-input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +.value-input[type=number] { + -moz-appearance: textfield; +} + +.adjust-btn { + background: 0 0; + border: 0; + color: var(--text-dark); + font-size: 1rem; + font-weight: 700; + cursor: pointer; + padding: 0 5px; + transition: color .2s; + line-height: 1; +} + +.adjust-btn:hover { + color: #fff; +} + +.control-group { + display: flex; + align-items: center; + gap: 15px; + padding: 0 10px; +} + +.control-group i { + font-size: 1.2rem; + cursor: pointer; + color: var(--text-light); + transition: color .2s; +} + +.control-group i:hover { + color: #fff; +} + +.fa-play, +.fa-pause { + color: var(--accent-green) !important; +} + +.divider { + width: 1px; + height: 25px; + background-color: var(--border-color); +} + +.info-display-group { + display: flex; + align-items: center; + gap: 5px; +} + +.info-display { + background-color: #1a1c1e; + padding: 5px 8px; + border-radius: 3px; + text-align: center; +} + +.info-display .label { + color: var(--text-dark); + font-size: .6rem; + text-transform: uppercase; +} + +.spacer { + flex-grow: 1; +} + +#metronome-btn { + background: 0 0; + border: 1px solid var(--text-dark); + color: var(--accent-green); + font-family: inherit; + font-weight: 700; + font-size: .8rem; + padding: 5px 10px; + border-radius: 3px; + cursor: pointer; + transition: all .2s; +} + +#metronome-btn:hover { + border-color: var(--text-light); + background-color: var(--bg-editor); +} + +#metronome-btn.active { + background-color: var(--accent-green); + color: var(--bg-body); + border-color: var(--accent-green); +} + +/* =============================================== */ +/* MODAL (CAIXA DE DIÁLOGO) +/* =============================================== */ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.7); + z-index: 2000; + display: flex; + justify-content: center; + align-items: center; + visibility: hidden; + opacity: 0; + transition: visibility 0s 0.3s, opacity 0.3s; +} + +.modal-overlay.visible { + visibility: visible; + opacity: 1; + transition: visibility 0s, opacity 0.3s; +} + +.modal-content { + background-color: var(--bg-body); + padding: 1.5rem 2rem; + border-radius: 6px; + border: 1px solid var(--border-color); + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); + width: 100%; + max-width: 500px; + position: relative; +} + +.modal-close { + position: absolute; + top: 10px; + right: 15px; + font-size: 1.5rem; + color: var(--text-dark); + cursor: pointer; + border: none; + background: none; +} + +.modal-close:hover { + color: var(--text-light); +} + +.modal-title { + margin-top: 0; + margin-bottom: 1.5rem; + color: var(--text-light); + text-align: center; +} + +.modal-section { + margin-bottom: 1.5rem; +} + +.modal-section h3 { + margin-top: 0; + margin-bottom: 0.8rem; + border-bottom: 1px solid var(--bg-toolbar); + padding-bottom: 0.5rem; +} + +.modal-button { + background-color: var(--bg-toolbar); + color: var(--text-light); + border: 1px solid var(--border-color); + padding: 0.8rem 1.5rem; + border-radius: 4px; + cursor: pointer; + font-size: 1rem; + transition: background-color 0.2s, border-color 0.2s; + width: 100%; +} + +.modal-button:hover { + background-color: #4a4f57; + border-color: #333; +} + +#server-projects-list .project-item { + background-color: var(--bg-editor); + padding: 10px 15px; + border-radius: 4px; + margin-bottom: 8px; + cursor: pointer; + transition: background-color 0.2s; +} + +#server-projects-list .project-item:hover { + background-color: var(--bg-body); + color: #fff; +} + + +/* =============================================== */ +/* ESTILOS RESPONSIVOS +/* =============================================== */ + +/* Para telas menores como laptops pequenos e tablets grandes */ +@media (max-width: 992px) { + .main-content { + padding: 1.5rem; /* Reduz o padding */ + } + + .beat-editor { + max-width: 100%; /* Permite que o editor use mais espaço */ + } +} + + +/* Para tablets e celulares */ +@media (max-width: 768px) { + body { + padding-left: 0 !important; /* Remove o padding fixo, !important para garantir */ + } + + .main-content { + padding: 1rem; + } + + /* A sidebar agora se sobrepõe ao conteúdo e fica escondida por padrão */ + .sample-browser { + transform: translateX(-100%); + width: 280px; /* Pode diminuir um pouco a largura */ + } + + /* Quando a sidebar for aberta, ela volta a posição original */ + body:not(.sidebar-hidden) .sample-browser { + transform: translateX(0); + } + + #sidebar-toggle { + left: 5px; /* Posição fixa do botão */ + } + + /* A toolbar global agora ocupa 100% da largura */ + .global-toolbar { + left: 0; + padding-left: 45px; /* Espaço para o botão do menu */ + } + + /* Quebra a linha dos itens da toolbar se não couberem */ + .editor-toolbar, + .control-group { + flex-wrap: wrap; + gap: 10px; + } + + /* Reorganiza a track para um layout vertical */ + .track-lane { + flex-direction: column; + align-items: stretch; /* Itens ocupam 100% da largura */ + gap: 15px; + padding: 15px; + } + + .track-info, + .track-controls { + width: 100%; + } + + .track-controls { + border-left: none; + padding-left: 0; + justify-content: space-around; /* Distribui melhor os knobs */ + } + + .step-sequencer { + width: 100%; + } + + /* Ajusta o modal para telas pequenas */ + .modal-content { + max-width: 90vw; + padding: 1.5rem 1rem; + } +} \ No newline at end of file diff --git a/assets/js/creations/audio.js b/assets/js/creations/audio.js new file mode 100644 index 0000000..9cdd9c9 --- /dev/null +++ b/assets/js/creations/audio.js @@ -0,0 +1,134 @@ +//TODO ver Tone.js + +// js/audio.js +import { appState } from "./state.js"; +import { highlightStep } from "./ui.js"; +import { getTotalSteps } from "./utils.js"; + +let audioContext; +let mainGainNode; + +export function getAudioContext() { + return audioContext; +} +export function getMainGainNode() { + return mainGainNode; +} + +export function initializeAudioContext() { + if (!audioContext) { + audioContext = new (window.AudioContext || window.webkitAudioContext)(); + mainGainNode = audioContext.createGain(); + mainGainNode.connect(audioContext.destination); + } + if (audioContext.state === "suspended") { + audioContext.resume(); + } +} + +export function playMetronomeSound(isDownbeat) { + initializeAudioContext(); + const oscillator = audioContext.createOscillator(); + const gainNode = audioContext.createGain(); + const frequency = isDownbeat ? 1000 : 800; + oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime); + oscillator.type = "sine"; + gainNode.gain.setValueAtTime(1, audioContext.currentTime); + gainNode.gain.exponentialRampToValueAtTime( + 0.00001, + audioContext.currentTime + 0.05 + ); + oscillator.connect(gainNode); + gainNode.connect(audioContext.destination); + oscillator.start(audioContext.currentTime); + oscillator.stop(audioContext.currentTime + 0.05); +} + +export function playSample(filePath, trackId) { + initializeAudioContext(); + if (!filePath) return; + + const track = trackId ? appState.tracks.find((t) => t.id == trackId) : null; + const audio = new Audio(filePath); + const source = audioContext.createMediaElementSource(audio); + + if (track && track.gainNode) { + source.connect(track.gainNode); + } else { + source.connect(mainGainNode); + } + + audio.play(); +} + +function tick() { + const totalSteps = getTotalSteps(); + if (totalSteps === 0) { + stopPlayback(); + return; + } + const lastStepIndex = + appState.currentStep === 0 ? totalSteps - 1 : appState.currentStep - 1; + highlightStep(lastStepIndex, false); + + if (appState.metronomeEnabled) { + const noteValue = + parseInt(document.getElementById("compasso-b-input").value, 10) || 4; + const stepsPerBeat = 16 / noteValue; + if (appState.currentStep % stepsPerBeat === 0) { + playMetronomeSound(appState.currentStep === 0); + } + } + + appState.tracks.forEach((track) => { + if (track.steps[appState.currentStep] && track.samplePath) { + playSample(track.samplePath, track.id); + } + }); + + highlightStep(appState.currentStep, true); + appState.currentStep = (appState.currentStep + 1) % totalSteps; +} + +export function startPlayback() { + if (appState.isPlaying || appState.tracks.length === 0) return; + initializeAudioContext(); + const bpm = parseInt(document.getElementById("bpm-input").value, 10) || 120; + const stepInterval = (60 * 1000) / (bpm * 4); + + if (appState.playbackIntervalId) clearInterval(appState.playbackIntervalId); + + appState.isPlaying = true; + document.getElementById("play-btn").classList.remove("fa-play"); + document.getElementById("play-btn").classList.add("fa-pause"); + + tick(); + appState.playbackIntervalId = setInterval(tick, stepInterval); +} + +export function stopPlayback() { + clearInterval(appState.playbackIntervalId); + appState.playbackIntervalId = null; + appState.isPlaying = false; + highlightStep(appState.currentStep - 1, false); + appState.currentStep = 0; + document.getElementById("play-btn").classList.remove("fa-pause"); + document.getElementById("play-btn").classList.add("fa-play"); +} + +export function rewindPlayback() { + appState.currentStep = 0; + if (!appState.isPlaying) { + document + .querySelectorAll(".step.playing") + .forEach((s) => s.classList.remove("playing")); + } +} + +export function togglePlayback() { + if (appState.isPlaying) { + stopPlayback(); + } else { + startPlayback(); + } +} diff --git a/assets/js/creations/config.js b/assets/js/creations/config.js new file mode 100644 index 0000000..4b0ef63 --- /dev/null +++ b/assets/js/creations/config.js @@ -0,0 +1,9 @@ +// js/config.js + +// Constantes usadas para o cálculo de posição de notas no arquivo .mmp +export const TICKS_PER_BAR = 192; +export const NOTE_LENGTH = 12; + +// Constantes para os valores padrão dos knobs +export const DEFAULT_VOLUME = 0.8; +export const DEFAULT_PAN = 0.0; diff --git a/assets/js/creations/file.js b/assets/js/creations/file.js new file mode 100644 index 0000000..d9d924d --- /dev/null +++ b/assets/js/creations/file.js @@ -0,0 +1,243 @@ +// js/file.js +import { appState } from "./state.js"; +import { getTotalSteps } from "./utils.js"; +import { renderApp } from "./ui.js"; +import { NOTE_LENGTH, TICKS_PER_BAR } from "./config.js"; +import { + initializeAudioContext, + getAudioContext, + getMainGainNode, +} from "./audio.js"; + +export async function handleFileLoad(file) { + let xmlContent = ""; + try { + if (file.name.toLowerCase().endsWith(".mmpz")) { + const jszip = new JSZip(); + const zip = await jszip.loadAsync(file); + const projectFile = Object.keys(zip.files).find((name) => + name.toLowerCase().endsWith(".mmp") + ); + if (!projectFile) + throw new Error( + "Não foi possível encontrar um arquivo .mmp dentro do .mmpz" + ); + xmlContent = await zip.files[projectFile].async("string"); + } else { + xmlContent = await file.text(); + } + parseMmpContent(xmlContent); + } catch (error) { + console.error("Erro ao carregar o projeto:", error); + alert(`Erro ao carregar projeto: ${error.message}`); + } +} + +export function parseMmpContent(xmlString) { + initializeAudioContext(); + const parser = new DOMParser(); + const xmlDoc = parser.parseFromString(xmlString, "application/xml"); + + appState.originalXmlDoc = xmlDoc; + const newTracks = []; + + const head = xmlDoc.querySelector("head"); + if (head) { + document.getElementById("bpm-input").value = + head.getAttribute("bpm") || 140; + document.getElementById("compasso-a-input").value = + head.getAttribute("timesig_numerator") || 4; + document.getElementById("compasso-b-input").value = + head.getAttribute("timesig_denominator") || 4; + } + const sampleTrackElements = xmlDoc.querySelectorAll( + 'instrument[name="audiofileprocessor"]' + ); + sampleTrackElements.forEach((instrumentNode) => { + const afpNode = instrumentNode.querySelector("audiofileprocessor"); + const instrumentTrackNode = instrumentNode.parentElement; + const trackNode = instrumentTrackNode.parentElement; + if (!afpNode || !instrumentTrackNode || !trackNode) return; + + const audioContext = getAudioContext(); + const mainGainNode = getMainGainNode(); + const totalSteps = parseInt( + trackNode.querySelector("pattern")?.getAttribute("steps") || + getTotalSteps(), + 10 + ); + const newSteps = new Array(totalSteps).fill(false); + const ticksPerStep = totalSteps > 0 ? TICKS_PER_BAR / totalSteps : 0; + + trackNode.querySelectorAll("pattern note").forEach((noteNode) => { + const pos = parseInt(noteNode.getAttribute("pos"), 10); + const stepIndex = Math.round(pos / ticksPerStep); + if (stepIndex < totalSteps) { + newSteps[stepIndex] = true; + } + }); + const newTrack = { + id: Date.now() + Math.random(), + name: + afpNode.getAttribute("src").split("/").pop() || + trackNode.getAttribute("name"), + samplePath: `samples/${afpNode.getAttribute("src")}`, + steps: newSteps, + volume: parseFloat(instrumentTrackNode.getAttribute("vol")) / 100, + pan: parseFloat(instrumentTrackNode.getAttribute("pan")) / 100, + gainNode: audioContext.createGain(), + pannerNode: audioContext.createStereoPanner(), + }; + newTrack.gainNode.connect(newTrack.pannerNode); + newTrack.pannerNode.connect(mainGainNode); + newTrack.gainNode.gain.value = newTrack.volume; + newTrack.pannerNode.pan.value = newTrack.pan; + newTracks.push(newTrack); + }); + appState.tracks = newTracks; + renderApp(); + console.log("Projeto carregado com sucesso!", appState); +} + +export function generateMmpFile() { + if (appState.originalXmlDoc) { + modifyAndSaveExistingMmp(); + } else { + generateNewMmp(); + } +} + +function generateNewMmp() { + console.log("Gerando novo arquivo .mmp do zero..."); + const bpm = document.getElementById("bpm-input").value; + const sig_num = document.getElementById("compasso-a-input").value; + const sig_den = document.getElementById("compasso-b-input").value; + const tracksXml = appState.tracks + .map((track) => createTrackXml(track)) + .join(""); + + const mmpContent = ` + + + + + + + + + ${tracksXml} + + + + + + + + + +

Feito com MMPCreator no https://alice.ufsj.edu.br/MMPSearch/creator

+]]>
+
+
`; + downloadFile(mmpContent, "novo_projeto.mmp"); +} + +function modifyAndSaveExistingMmp() { + console.log("Modificando arquivo .mmp existente..."); + const xmlDoc = appState.originalXmlDoc.cloneNode(true); + const head = xmlDoc.querySelector("head"); + if (head) { + head.setAttribute("bpm", document.getElementById("bpm-input").value); + head.setAttribute( + "timesig_numerator", + document.getElementById("compasso-a-input").value + ); + head.setAttribute( + "timesig_denominator", + document.getElementById("compasso-b-input").value + ); + } + const bbTrackContainer = xmlDoc.querySelector("bbtrack > trackcontainer"); + if (bbTrackContainer) { + const oldSampleTracks = bbTrackContainer.querySelectorAll( + 'instrument[name="audiofileprocessor"]' + ); + oldSampleTracks.forEach((node) => node.closest("track").remove()); + const tracksXml = appState.tracks + .map((track) => createTrackXml(track)) + .join(""); + const tempDoc = new DOMParser().parseFromString( + `${tracksXml}`, + "application/xml" + ); + Array.from(tempDoc.documentElement.children).forEach((newTrackNode) => { + bbTrackContainer.appendChild(newTrackNode); + }); + } + + const serializer = new XMLSerializer(); + const mmpContent = serializer.serializeToString(xmlDoc); + downloadFile(mmpContent, "projeto_editado.mmp"); +} + +function createTrackXml(track) { + if (!track.samplePath) return ""; + const totalSteps = track.steps.length || getTotalSteps(); + const ticksPerStep = totalSteps > 0 ? TICKS_PER_BAR / totalSteps : 0; + const lmmsVolume = Math.round(track.volume * 100); + const lmmsPan = Math.round(track.pan * 100); + const sampleSrc = track.samplePath.replace("samples/", ""); + const notesXml = track.steps + .map((isActive, index) => { + if (isActive) { + const notePos = Math.round(index * ticksPerStep); + return ``; + } + return ""; + }) + .join("\n "); + return ` + + + + + + + + + ${notesXml} + + `; +} + +function downloadFile(content, fileName) { + const blob = new Blob([content], { type: "application/xml;charset=utf-8" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = fileName; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); +} + +// (ALTERADO) Adiciona export na frente da função +export async function loadProjectFromServer(fileName) { + try { + const response = await fetch(`mmp/${fileName}`); + if (!response.ok) + throw new Error(`Não foi possível carregar o arquivo ${fileName}`); + const xmlContent = await response.text(); + parseMmpContent(xmlContent); + // Retorna true em caso de sucesso + return true; + } catch (error) { + console.error("Erro ao carregar projeto do servidor:", error); + alert(`Erro ao carregar projeto: ${error.message}`); + // Retorna false em caso de falha + return false; + } +} diff --git a/assets/js/creations/main.js b/assets/js/creations/main.js new file mode 100644 index 0000000..65634ab --- /dev/null +++ b/assets/js/creations/main.js @@ -0,0 +1,121 @@ +// js/main.js +import { + appState, + addTrackToState, + removeLastTrackFromState, +} from "./state.js"; +import { + togglePlayback, + stopPlayback, + rewindPlayback, + initializeAudioContext, +} from "./audio.js"; +import { handleFileLoad, generateMmpFile } from "./file.js"; +import { + renderApp, + redrawSequencer, + loadAndRenderSampleBrowser, + showOpenProjectModal, + closeOpenProjectModal, +} from "./ui.js"; +import { adjustValue, enforceNumericInput } from "./utils.js"; + +// --- INICIALIZAÇÃO E EVENTOS FINAIS --- +document.addEventListener("DOMContentLoaded", () => { + const newProjectBtn = document.getElementById("new-project-btn"); + const openMmpBtn = document.getElementById("open-mmp-btn"); + const saveMmpBtn = document.getElementById("save-mmp-btn"); + const addInstrumentBtn = document.getElementById("add-instrument-btn"); + const removeInstrumentBtn = document.getElementById("remove-instrument-btn"); + const playBtn = document.getElementById("play-btn"); + const stopBtn = document.getElementById("stop-btn"); + const rewindBtn = document.getElementById("rewind-btn"); + const metronomeBtn = document.getElementById("metronome-btn"); + const mmpFileInput = document.getElementById("mmp-file-input"); + const openProjectModal = document.getElementById("open-project-modal"); + const openModalCloseBtn = document.getElementById("open-modal-close-btn"); + const loadFromComputerBtn = document.getElementById("load-from-computer-btn"); + const sidebarToggle = document.getElementById("sidebar-toggle"); + + newProjectBtn.addEventListener("click", () => { + if ( + appState.tracks.length > 0 && + !confirm("Você tem certeza? Alterações não salvas serão perdidas.") + ) + return; + Object.assign(appState, { + tracks: [], + isPlaying: false, + playbackIntervalId: null, + currentStep: 0, + metronomeEnabled: false, + originalXmlDoc: null, + }); + renderApp(); + }); + + openMmpBtn.addEventListener("click", showOpenProjectModal); + loadFromComputerBtn.addEventListener("click", () => mmpFileInput.click()); + mmpFileInput.addEventListener("change", (event) => { + const file = event.target.files[0]; + if (file) { + handleFileLoad(file); + closeOpenProjectModal(); + } + }); + saveMmpBtn.addEventListener("click", generateMmpFile); + addInstrumentBtn.addEventListener("click", addTrackToState); + removeInstrumentBtn.addEventListener("click", removeLastTrackFromState); + playBtn.addEventListener("click", togglePlayback); + stopBtn.addEventListener("click", stopPlayback); + rewindBtn.addEventListener("click", rewindPlayback); + metronomeBtn.addEventListener("click", () => { + initializeAudioContext(); + appState.metronomeEnabled = !appState.metronomeEnabled; + metronomeBtn.classList.toggle("active", appState.metronomeEnabled); + }); + openModalCloseBtn.addEventListener("click", closeOpenProjectModal); + openProjectModal.addEventListener("click", (e) => { + if (e.target === openProjectModal) closeOpenProjectModal(); + }); + sidebarToggle.addEventListener("click", () => { + document.body.classList.toggle("sidebar-hidden"); + const icon = sidebarToggle.querySelector("i"); + icon.className = document.body.classList.contains("sidebar-hidden") + ? "fa-solid fa-caret-right" + : "fa-solid fa-caret-left"; + }); + + const inputs = document.querySelectorAll(".value-input"); + inputs.forEach((input) => { + input.addEventListener("input", (event) => { + enforceNumericInput(event); + if (appState.isPlaying && event.target.id.startsWith("compasso-")) { + stopPlayback(); + } + if (event.target.id.startsWith("compasso-")) { + redrawSequencer(); + } + }); + input.addEventListener("wheel", (event) => { + event.preventDefault(); + const step = event.deltaY < 0 ? 1 : -1; + adjustValue(event.target, step); + }); + }); + + const buttons = document.querySelectorAll(".adjust-btn"); + buttons.forEach((button) => { + button.addEventListener("click", () => { + const targetId = button.dataset.target + "-input"; + const targetInput = document.getElementById(targetId); + if (targetInput) { + adjustValue(targetInput, step); + } + }); + }); + + // Inicia a aplicação + loadAndRenderSampleBrowser(); + renderApp(); +}); diff --git a/assets/js/creations/state.js b/assets/js/creations/state.js new file mode 100644 index 0000000..c58a477 --- /dev/null +++ b/assets/js/creations/state.js @@ -0,0 +1,90 @@ +// js/state.js +import { DEFAULT_VOLUME, DEFAULT_PAN } from "./config.js"; +import { + initializeAudioContext, + getAudioContext, + getMainGainNode, +} from "./audio.js"; +import { renderApp } from "./ui.js"; + +// O "cérebro" da aplicação +export let appState = { + tracks: [], + isPlaying: false, + playbackIntervalId: null, + currentStep: 0, + metronomeEnabled: false, + originalXmlDoc: null, +}; + +export function addTrackToState() { + initializeAudioContext(); + const audioContext = getAudioContext(); + const mainGainNode = getMainGainNode(); + + const newTrack = { + id: Date.now(), + name: "novo instrumento", + samplePath: null, + steps: [], + volume: DEFAULT_VOLUME, + pan: DEFAULT_PAN, + gainNode: audioContext.createGain(), + pannerNode: audioContext.createStereoPanner(), + }; + newTrack.gainNode.connect(newTrack.pannerNode); + newTrack.pannerNode.connect(mainGainNode); + newTrack.gainNode.gain.value = newTrack.volume; + newTrack.pannerNode.pan.value = newTrack.pan; + + appState.tracks.push(newTrack); + renderApp(); +} + +export function removeLastTrackFromState() { + appState.tracks.pop(); + renderApp(); +} + +export function updateTrackSample(trackId, samplePath) { + const track = appState.tracks.find((t) => t.id == trackId); + if (track) { + track.samplePath = samplePath; + track.name = samplePath.split("/").pop(); + } + renderApp(); +} + +export function toggleStepState(trackId, stepIndex) { + const track = appState.tracks.find((t) => t.id == trackId); + if (track) { + track.steps[stepIndex] = !track.steps[stepIndex]; + } +} + +export function updateTrackVolume(trackId, volume) { + const track = appState.tracks.find((t) => t.id == trackId); + const audioContext = getAudioContext(); + if (track) { + const clampedVolume = Math.max(0, Math.min(1.5, volume)); + track.volume = clampedVolume; + if (track.gainNode) { + track.gainNode.gain.setValueAtTime( + clampedVolume, + audioContext.currentTime + ); + } + } +} + +export function updateTrackPan(trackId, pan) { + const track = appState.tracks.find((t) => t.id == trackId); + const audioContext = getAudioContext(); + if (track) { + const clampedPan = Math.max(-1, Math.min(1, pan)); + track.pan = clampedPan; + if (track.pannerNode) { + track.pannerNode.pan.setValueAtTime(clampedPan, audioContext.currentTime); + } + } +} diff --git a/assets/js/creations/ui.js b/assets/js/creations/ui.js new file mode 100644 index 0000000..3ed6ecd --- /dev/null +++ b/assets/js/creations/ui.js @@ -0,0 +1,319 @@ +// js/ui.js +import { + appState, + toggleStepState, + updateTrackSample, + updateTrackVolume, + updateTrackPan, +} from "./state.js"; +import { playSample } from "./audio.js"; +import { getTotalSteps } from "./utils.js"; +import { loadProjectFromServer } from "./file.js"; // (CORREÇÃO) Importa a função que faltava + +// RENDERIZAÇÃO PRINCIPAL +export function renderApp() { + const trackContainer = document.getElementById("track-container"); + trackContainer.innerHTML = ""; + appState.tracks.forEach((trackData) => { + const trackLane = document.createElement("div"); + trackLane.className = "track-lane"; + trackLane.dataset.trackId = trackData.id; + + trackLane.innerHTML = ` +
${trackData.name}
+
+
+
+
+
+ VOL +
+
+
+
+
+ PAN +
+
+
+ `; + + trackLane.addEventListener("dragover", (e) => { + e.preventDefault(); + trackLane.classList.add("drag-over"); + }); + trackLane.addEventListener("dragleave", () => + trackLane.classList.remove("drag-over") + ); + trackLane.addEventListener("drop", (e) => { + e.preventDefault(); + trackLane.classList.remove("drag-over"); + const filePath = e.dataTransfer.getData("text/plain"); + if (filePath) { + updateTrackSample(trackData.id, filePath); + } + }); + + trackContainer.appendChild(trackLane); + + const volumeKnob = trackLane.querySelector(".knob[data-control='volume']"); + addKnobInteraction(volumeKnob); + updateKnobVisual(volumeKnob, "volume"); + + const panKnob = trackLane.querySelector(".knob[data-control='pan']"); + addKnobInteraction(panKnob); + updateKnobVisual(panKnob, "pan"); + }); + redrawSequencer(); +} + +export function redrawSequencer() { + const beatsPerBar = + parseInt(document.getElementById("compasso-a-input").value, 10) || 4; + const totalSteps = getTotalSteps(); + document.querySelectorAll(".step-sequencer").forEach((container) => { + const parentTrackElement = container.closest(".track-lane"); + const trackId = parentTrackElement.dataset.trackId; + const trackData = appState.tracks.find((t) => t.id == trackId); + if (trackData && trackData.steps.length !== totalSteps) { + const newStepsState = new Array(totalSteps).fill(false); + for (let i = 0; i < Math.min(trackData.steps.length, totalSteps); i++) { + newStepsState[i] = trackData.steps[i]; + } + trackData.steps = newStepsState; + } + container.innerHTML = ""; + for (let i = 0; i < totalSteps; i++) { + const stepWrapper = document.createElement("div"); + stepWrapper.className = "step-wrapper"; + const stepElement = document.createElement("div"); + stepElement.className = "step"; + if (trackData && trackData.steps[i] === true) { + stepElement.classList.add("active"); + } + stepElement.addEventListener("click", () => { + toggleStepState(trackData.id, i); + stepElement.classList.toggle("active"); + if (trackData && trackData.samplePath) { + playSample(trackData.samplePath, trackData.id); + } + }); + const groupIndex = Math.floor(i / beatsPerBar); + if (groupIndex % 2 === 0) { + stepElement.classList.add("step-dark"); + } + if (i > 0 && i % beatsPerBar === 0) { + const marker = document.createElement("div"); + marker.className = "step-marker"; + marker.textContent = i; + stepWrapper.appendChild(marker); + } + stepWrapper.appendChild(stepElement); + container.appendChild(stepWrapper); + } + }); +} + +// LÓGICA DE INTERAÇÃO DOS KNOBS +function addKnobInteraction(knobElement) { + const controlType = knobElement.dataset.control; + knobElement.addEventListener("mousedown", (e) => { + if (e.button === 1) { + e.preventDefault(); + const trackId = knobElement.dataset.trackId; + const defaultValue = controlType === "volume" ? 0.8 : 0.0; + if (controlType === "volume") { + updateTrackVolume(trackId, defaultValue); + } else { + updateTrackPan(trackId, defaultValue); + } + } + }); + knobElement.addEventListener("mousedown", (e) => { + if (e.button !== 0) return; + e.preventDefault(); + const trackId = knobElement.dataset.trackId; + const track = appState.tracks.find((t) => t.id == trackId); + if (!track) return; + const startY = e.clientY; + const startValue = controlType === "volume" ? track.volume : track.pan; + document.body.classList.add("knob-dragging"); + function onMouseMove(moveEvent) { + const deltaY = startY - moveEvent.clientY; + const sensitivity = controlType === "volume" ? 150 : 200; + const newValue = startValue + deltaY / sensitivity; + if (controlType === "volume") { + updateTrackVolume(trackId, newValue); + } else { + updateTrackPan(trackId, newValue); + } + } + function onMouseUp() { + document.body.classList.remove("knob-dragging"); + document.removeEventListener("mousemove", onMouseMove); + document.removeEventListener("mouseup", onMouseUp); + } + document.addEventListener("mousemove", onMouseMove); + document.addEventListener("mouseup", onMouseUp); + }); + knobElement.addEventListener("wheel", (e) => { + e.preventDefault(); + const trackId = knobElement.dataset.trackId; + const track = appState.tracks.find((t) => t.id == trackId); + if (!track) return; + const step = 0.05; + const direction = e.deltaY < 0 ? 1 : -1; + if (controlType === "volume") { + const newValue = track.volume + direction * step; + updateTrackVolume(trackId, newValue); + } else { + const newValue = track.pan + direction * step; + updateTrackPan(trackId, newValue); + } + }); +} + +function updateKnobVisual(knobElement, controlType) { + const trackId = knobElement.dataset.trackId; + const track = appState.tracks.find((t) => t.id == trackId); + if (!track) return; + const indicator = knobElement.querySelector(".knob-indicator"); + if (!indicator) return; + const minAngle = -135; + const maxAngle = 135; + let percentage = 0.5; + let title = ""; + if (controlType === "volume") { + const value = track.volume; + const clampedValue = Math.max(0, Math.min(1.5, value)); + percentage = clampedValue / 1.5; + title = `Volume: ${Math.round(clampedValue * 100)}%`; + } else { + const value = track.pan; + const clampedValue = Math.max(-1, Math.min(1, value)); + percentage = (clampedValue + 1) / 2; + const panDisplay = Math.round(clampedValue * 100); + title = `Pan: ${ + panDisplay === 0 + ? "Centro" + : panDisplay < 0 + ? `${-panDisplay} L` + : `${panDisplay} R` + }`; + } + const angle = minAngle + percentage * (maxAngle - minAngle); + indicator.style.transform = `translateX(-50%) rotate(${angle}deg)`; + knobElement.title = title; +} + +export function highlightStep(stepIndex, isActive) { + if (stepIndex < 0) return; + document.querySelectorAll(".track-lane").forEach((track) => { + const stepWrapper = track.querySelector( + `.step-sequencer .step-wrapper:nth-child(${stepIndex + 1})` + ); + if (stepWrapper) { + const stepElement = stepWrapper.querySelector(".step"); + if (stepElement) { + stepElement.classList.toggle("playing", isActive); + } + } + }); +} + +// LÓGICA DA SIDEBAR E MODAL +export async function loadAndRenderSampleBrowser() { + const browserContent = document.getElementById("browser-content"); + try { + const response = await fetch("metadata/samples-manifest.json"); + if (!response.ok) { + throw new Error("Arquivo samples-manifest.json não encontrado."); + } + const fileTree = await response.json(); + renderFileTree(fileTree, browserContent, "src/samples"); + } catch (error) { + console.error("Erro ao carregar samples:", error); + browserContent.innerHTML = `

${error.message}

`; + } +} + +function renderFileTree(tree, parentElement, currentPath) { + parentElement.innerHTML = ""; + const ul = document.createElement("ul"); + const sortedKeys = Object.keys(tree).sort((a, b) => { + const aIsFile = tree[a]._isFile; + const bIsFile = tree[b]._isFile; + if (aIsFile === bIsFile) return a.localeCompare(b); + return aIsFile ? 1 : -1; + }); + for (const key of sortedKeys) { + const node = tree[key]; + const li = document.createElement("li"); + const newPath = `${currentPath}/${key}`; + if (node._isFile) { + li.innerHTML = ` ${key}`; + li.setAttribute("draggable", true); + li.addEventListener("click", (e) => { + e.stopPropagation(); + playSample(newPath, null); + }); + li.addEventListener("dragstart", (e) => { + e.dataTransfer.setData("text/plain", newPath); + e.dataTransfer.effectAllowed = "copy"; + }); + ul.appendChild(li); + } else { + li.className = "directory"; + li.innerHTML = ` ${key}`; + const nestedUl = document.createElement("ul"); + renderFileTree(node, nestedUl, newPath); + li.appendChild(nestedUl); + li.addEventListener("click", (e) => { + e.stopPropagation(); + li.classList.toggle("open"); + }); + ul.appendChild(li); + } + } + parentElement.appendChild(ul); +} + +export async function showOpenProjectModal() { + const openProjectModal = document.getElementById("open-project-modal"); + const serverProjectsList = document.getElementById("server-projects-list"); + serverProjectsList.innerHTML = "

Carregando...

"; + openProjectModal.classList.add("visible"); + try { + const response = await fetch("metadata/mmp-manifest.json"); + if (!response.ok) + throw new Error("Arquivo mmp-manifest.json não encontrado."); + const projects = await response.json(); + + serverProjectsList.innerHTML = ""; + if (projects.length === 0) { + serverProjectsList.innerHTML = + '

Nenhum projeto encontrado no servidor.

'; + } + + projects.forEach((projectName) => { + const projectItem = document.createElement("div"); + projectItem.className = "project-item"; + projectItem.textContent = projectName; + projectItem.addEventListener("click", async () => { + const success = await loadProjectFromServer(projectName); + if (success) { + closeOpenProjectModal(); + } + }); + serverProjectsList.appendChild(projectItem); + }); + } catch (error) { + console.error("Erro ao carregar lista de projetos:", error); + serverProjectsList.innerHTML = `

${error.message}

`; + } +} + +export function closeOpenProjectModal() { + const openProjectModal = document.getElementById("open-project-modal"); + openProjectModal.classList.remove("visible"); +} diff --git a/assets/js/creations/utils.js b/assets/js/creations/utils.js new file mode 100644 index 0000000..ca7f2d8 --- /dev/null +++ b/assets/js/creations/utils.js @@ -0,0 +1,27 @@ +// js/utils.js + +export function getTotalSteps() { + const compassoAInput = document.getElementById("compasso-a-input"); + const compassoBInput = document.getElementById("compasso-b-input"); + const beatsPerBar = parseInt(compassoAInput.value, 10) || 4; + const noteValue = parseInt(compassoBInput.value, 10) || 4; + const subdivisions = Math.round(16 / noteValue); + return beatsPerBar * subdivisions; +} + +export function enforceNumericInput(event) { + event.target.value = event.target.value.replace(/[^0-9]/g, ""); +} + +export function adjustValue(inputElement, step) { + let currentValue = parseInt(inputElement.value, 10) || 0; + let min = parseInt(inputElement.dataset.min, 10); + let max = parseInt(inputElement.dataset.max, 10); + let newValue = currentValue + step; + if (!isNaN(min) && newValue < min) newValue = min; + if (!isNaN(max) && newValue > max) newValue = max; + inputElement.value = newValue; + + // Dispara um evento 'input' para que outros listeners (como o que redesenha o sequenciador) sejam acionados. + inputElement.dispatchEvent(new Event("input", { bubbles: true })); +} diff --git a/assets/js/search.js b/assets/js/search.js index 26b234f..aa74668 100644 --- a/assets/js/search.js +++ b/assets/js/search.js @@ -1,108 +1,123 @@ -document.addEventListener("DOMContentLoaded", function() { - var fileItemsMMP = document.querySelectorAll('#file-list-mmp .file-item'); - var fileItemsWAV = document.querySelectorAll('#file-list-wav .file-wav-item'); +document.addEventListener("DOMContentLoaded", function () { + var fileItemsMMP = document.querySelectorAll("#file-list-mmp .file-item"); + var fileItemsWAV = document.querySelectorAll("#file-list-wav .file-wav-item"); // Função para exibir apenas os arquivos WAV correspondentes aos instrumentos encontrados nos projetos MMP function showWAVFilesByInstrument(selectedInstrument) { - fileItemsWAV.forEach(function(item) { - var fileName = item.getAttribute('data-file').toLowerCase(); + fileItemsWAV.forEach(function (item) { + var fileName = item.getAttribute("data-file").toLowerCase(); if (fileName.includes(selectedInstrument)) { - item.style.display = 'block'; + item.style.display = "block"; } else { - item.style.display = 'none'; + item.style.display = "none"; } }); } // Buscar por instrumento usando o campo de entrada para MMP - var searchButton = document.getElementById('search-button'); - searchButton.addEventListener('click', function() { - var searchInput = document.getElementById('instrument-search').value.trim().toLowerCase(); - if (searchInput === '') { + var searchButton = document.getElementById("search-button"); + searchButton.addEventListener("click", function () { + var searchInput = document + .getElementById("instrument-search") + .value.trim() + .toLowerCase(); + if (searchInput === "") { resetSearch(); return; } - fileItemsMMP.forEach(function(item) { - var instrumentsList = item.querySelectorAll('.instrument-list .instrument-name'); + fileItemsMMP.forEach(function (item) { + var instrumentsList = item.querySelectorAll( + ".instrument-list .instrument-name" + ); var hasInstrument = false; - instrumentsList.forEach(function(instrument) { - var instrumentName = instrument.getAttribute('data-instrument').toLowerCase(); + instrumentsList.forEach(function (instrument) { + var instrumentName = instrument + .getAttribute("data-instrument") + .toLowerCase(); if (instrumentName.includes(searchInput)) { hasInstrument = true; } }); if (hasInstrument) { - item.style.display = 'block'; + item.style.display = "block"; } else { - item.style.display = 'none'; + item.style.display = "none"; } }); // Exibir a lista de arquivos MMP após a busca - document.getElementById('file-list-mmp').style.display = 'block'; + document.getElementById("file-list-mmp").style.display = "block"; }); // Buscar por nome de arquivo WAV usando o campo de entrada - var searchWavButton = document.getElementById('search-wav-button'); - searchWavButton.addEventListener('click', function() { - var searchInput = document.getElementById('file-wav-search').value.trim().toLowerCase(); - if (searchInput === '') { + var searchWavButton = document.getElementById("search-wav-button"); + searchWavButton.addEventListener("click", function () { + var searchInput = document + .getElementById("file-wav-search") + .value.trim() + .toLowerCase(); + if (searchInput === "") { resetSearch(); return; } - fileItemsWAV.forEach(function(item) { - var fileName = item.querySelector('span').textContent.toLowerCase(); + fileItemsWAV.forEach(function (item) { + var fileName = item.querySelector("span").textContent.toLowerCase(); if (fileName.includes(searchInput)) { - item.style.display = 'block'; + item.style.display = "block"; } else { - item.style.display = 'none'; + item.style.display = "none"; } }); // Exibir a lista de arquivos WAV após a busca - document.getElementById('file-list-wav').style.display = 'block'; + document.getElementById("file-list-wav").style.display = "block"; }); // Buscar por instrumento ou nome de arquivo WAV usando o campo de entrada combinado - var searchBothButton = document.getElementById('search-both-button'); - searchBothButton.addEventListener('click', function() { - var searchInput = document.getElementById('instrument-wav-search').value.trim().toLowerCase(); - if (searchInput === '') { + var searchBothButton = document.getElementById("search-both-button"); + searchBothButton.addEventListener("click", function () { + var searchInput = document + .getElementById("instrument-wav-search") + .value.trim() + .toLowerCase(); + if (searchInput === "") { resetSearch(); return; } // Buscar em arquivos MMP por instrumento - fileItemsMMP.forEach(function(item) { - var instrumentsList = item.querySelectorAll('.instrument-list .instrument-name'); + fileItemsMMP.forEach(function (item) { + var instrumentsList = item.querySelectorAll( + ".instrument-list .instrument-name" + ); var hasInstrument = false; - instrumentsList.forEach(function(instrument) { - var instrumentName = instrument.getAttribute('data-instrument').toLowerCase(); + instrumentsList.forEach(function (instrument) { + var instrumentName = instrument + .getAttribute("data-instrument") + .toLowerCase(); if (instrumentName.includes(searchInput)) { hasInstrument = true; // Mostrar arquivo WAV correspondente ao instrumento - showWAVFilesByInstrument(item.getAttribute('data-file')); + showWAVFilesByInstrument(item.getAttribute("data-file")); } }); if (hasInstrument) { - item.style.display = 'block'; + item.style.display = "block"; } else { - item.style.display = 'none'; + item.style.display = "none"; } }); // Exibir as listas de arquivos após a busca - document.getElementById('file-list-mmp').style.display = 'block'; - document.getElementById('file-list-wav').style.display = 'block'; + document.getElementById("file-list-mmp").style.display = "block"; + document.getElementById("file-list-wav").style.display = "block"; }); // Função para resetar a busca function resetSearch() { - fileItemsMMP.forEach(function(item) { - item.style.display = 'block'; + fileItemsMMP.forEach(function (item) { + item.style.display = "block"; }); - fileItemsWAV.forEach(function(item) { - item.style.display = 'block'; + fileItemsWAV.forEach(function (item) { + item.style.display = "block"; }); - document.getElementById('file-list-mmp').style.display = 'none'; - document.getElementById('file-list-wav').style.display = 'none'; + document.getElementById("file-list-mmp").style.display = "none"; + document.getElementById("file-list-wav").style.display = "none"; } - }); - diff --git a/automation.html b/automation.html index cb0c9a5..d69abea 100644 --- a/automation.html +++ b/automation.html @@ -3,18 +3,19 @@ layout: default title: Projetos com a tag Automation permalink: /automation/ --- - -
-
- {% include sidebar.html %} -
+ + +
+
{% include sidebar.html %}
-
+
-

Projetos que possuem a tag automation:

+

+ Projetos que possuem a tag automation: +

@@ -26,99 +27,104 @@ permalink: /automation/
- {% for projeto in site.data.all %} - {% if projeto.tags.TAG contains "automation" %} -
-
- - {% assign file_url = projeto.file | downcase - | replace: ' ', '-' - | replace: 'ç', 'c' - | replace: 'ã', 'a' - | replace: 'á', 'a' - | replace: 'â', 'a' - | replace: 'é', 'e' - | replace: 'ê', 'e' - | replace: 'í', 'i' - | replace: 'ó', 'o' - | replace: 'ô', 'o' - | replace: 'õ', 'o' - | replace: 'ú', 'u' %} + {% for projeto in site.data.all %} {% if projeto.tags.TAG contains + "automation" %} +
+
+ + {% assign file_url = projeto.file | downcase | replace: ' ', '-' | + replace: 'ç', 'c' | replace: 'ã', 'a' | replace: 'á', 'a' | replace: + 'â', 'a' | replace: 'é', 'e' | replace: 'ê', 'e' | replace: 'í', 'i' | + replace: 'ó', 'o' | replace: 'ô', 'o' | replace: 'õ', 'o' | replace: + 'ú', 'u' %} - - {{ projeto.file }} - + + {{ projeto.file }} + - - {% if projeto.tags.automation and projeto.tags.automation.size > 0 %} -
-

Automation:

-
    - {% for automation in projeto.tags.automation %} - {% if automation != "" %} -
  • {{ automation }}
  • - {% endif %} - {% endfor %} -
-
- {% endif %} -
+ + {% if projeto.tags.automation and projeto.tags.automation.size > 0 %} +
+

Automation:

+
    + {% for automation in projeto.tags.automation %} {% if automation + != "" %} +
  • + {{ automation }} +
  • + {% endif %} {% endfor %} +
- {% endif %} - {% endfor %} + {% endif %} +
+
+ {% endif %} {% endfor %}
\ No newline at end of file + diff --git a/bassline.html b/bassline.html index 9e08279..00e482c 100644 --- a/bassline.html +++ b/bassline.html @@ -3,18 +3,19 @@ layout: default title: Projetos com a tag Bassline permalink: /bassline/ --- - -
-
- {% include sidebar.html %} -
+ + +
+
{% include sidebar.html %}
-
+
-

Projetos que possuem a tag bassline:

+

+ Projetos que possuem a tag bassline: +

@@ -26,109 +27,111 @@ permalink: /bassline/
- {% for projeto in site.data.all %} - {% if projeto.tags.TAG contains "bassline" %} -
-
- - {% assign file_url = projeto.file | downcase - | replace: ' ', '-' - | replace: 'ç', 'c' - | replace: 'ã', 'a' - | replace: 'á', 'a' - | replace: 'â', 'a' - | replace: 'é', 'e' - | replace: 'ê', 'e' - | replace: 'í', 'i' - | replace: 'ó', 'o' - | replace: 'ô', 'o' - | replace: 'õ', 'o' - | replace: 'ú', 'u' %} + {% for projeto in site.data.all %} {% if projeto.tags.TAG contains + "bassline" %} +
+
+ + {% assign file_url = projeto.file | downcase | replace: ' ', '-' | + replace: 'ç', 'c' | replace: 'ã', 'a' | replace: 'á', 'a' | replace: + 'â', 'a' | replace: 'é', 'e' | replace: 'ê', 'e' | replace: 'í', 'i' | + replace: 'ó', 'o' | replace: 'ô', 'o' | replace: 'õ', 'o' | replace: + 'ú', 'u' %} - - {{ projeto.file }} - + + {{ projeto.file }} + - - {% if projeto.tags.bassline and projeto.tags.bassline.size > 0 %} -
-

Bassline:

-
    - {% for bassline in projeto.tags.bassline %} - {% if bassline != "" %} -
  • {{ bassline }}
  • - {% endif %} - {% endfor %} -
-
- {% endif %} -
+ + {% if projeto.tags.bassline and projeto.tags.bassline.size > 0 %} +
+

Bassline:

+
    + {% for bassline in projeto.tags.bassline %} {% if bassline != "" + %} +
  • + {{ bassline }} +
  • + {% endif %} {% endfor %} +
- {% endif %} - {% endfor %} + {% endif %} +
+
+ {% endif %} {% endfor %}
+ + + + diff --git a/scripts/creation/generateManifest.py b/scripts/creation/generateManifest.py new file mode 100644 index 0000000..becbd96 --- /dev/null +++ b/scripts/creation/generateManifest.py @@ -0,0 +1,101 @@ +import os +import json + +# --- Configuração de Caminhos Dinâmicos --- +# Descobre o caminho absoluto do script que está sendo executado. +# __file__ é uma variável especial do Python que contém o caminho para o arquivo atual. +SCRIPT_PATH = os.path.abspath(__file__) + +# Descobre o diretório onde o script está (ex: /.../mmpSearch/scripts/creation) +SCRIPT_DIR = os.path.dirname(SCRIPT_PATH) + +# Define a raiz do projeto subindo dois níveis de diretório (de 'creation' para 'scripts', e de 'scripts' para 'mmpSearch') +PROJECT_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..')) + +print(f"Raiz do projeto detectada em: {PROJECT_ROOT}") + + +# --- Configuração dos Manifestos --- +# Os caminhos aqui são relativos à RAIZ DO PROJETO. +CONFIGS = [ + { + "source_dir": "src/samples", + "output_file": "metadata/samples-manifest.json", + "scan_type": "tree" + }, + { + "source_dir": "mmp", + "output_file": "metadata/mmp-manifest.json", + "scan_type": "list", + "extensions": ['.mmp', '.mmpz'] + } +] + +def scan_directory_tree(path): + """ + Função recursiva que escaneia um diretório e constrói uma + estrutura de dicionário (árvore) representando as pastas e arquivos. + """ + tree = {} + if not os.path.isdir(path): + return tree + for item in os.listdir(path): + full_path = os.path.join(path, item) + if os.path.isdir(full_path): + tree[item] = scan_directory_tree(full_path) + else: + # (CORREÇÃO) Volte a usar o objeto que o JavaScript espera. + tree[item] = {"_isFile": True} + return tree + +def scan_directory_list(path, allowed_extensions): + """ + Função que escaneia um diretório e retorna uma lista simples + de nomes de arquivos, filtrando por extensões permitidas. + """ + file_list = [] + if not os.path.isdir(path): # Adiciona verificação + return file_list + for item in os.listdir(path): + full_path = os.path.join(path, item) + if os.path.isfile(full_path) and any(item.lower().endswith(ext) for ext in allowed_extensions): + file_list.append(item) + return sorted(file_list) + +# --- Execução Principal do Script --- +if __name__ == "__main__": + print("\nIniciando geração de arquivos de manifesto...") + + for config in CONFIGS: + # Monta os caminhos ABSOLUTOS usando a raiz do projeto + source_dir_abs = os.path.join(PROJECT_ROOT, config["source_dir"]) + output_file_abs = os.path.join(PROJECT_ROOT, config["output_file"]) + scan_type = config["scan_type"] + + print(f"\nProcessando '{config['source_dir']}' -> '{config['output_file']}'...") + + if not os.path.isdir(source_dir_abs): + print(f"AVISO: A pasta de origem '{source_dir_abs}' não foi encontrada. Arquivo não será gerado.") + continue + + result_data = None + try: + if scan_type == "tree": + result_data = scan_directory_tree(source_dir_abs) + elif scan_type == "list": + extensions = config.get("extensions", []) + result_data = scan_directory_list(source_dir_abs, extensions) + + if result_data is not None: + # Garante que o diretório de saída exista antes de salvar + output_dir = os.path.dirname(output_file_abs) + os.makedirs(output_dir, exist_ok=True) + + with open(output_file_abs, 'w', encoding='utf-8') as f: + json.dump(result_data, f, indent=2, ensure_ascii=False) + print(f"SUCESSO: Arquivo '{output_file_abs}' gerado!") + + except Exception as e: + print(f"ERRO inesperado ao processar a pasta '{source_dir_abs}': {e}") + + print("\nGeração de manifestos concluída.") \ No newline at end of file diff --git a/scripts/handler/automations/automations.py b/scripts/handler/automations/automations.py index b082281..5c7b49c 100644 --- a/scripts/handler/automations/automations.py +++ b/scripts/handler/automations/automations.py @@ -25,7 +25,9 @@ def parse_automation(file_path): if automationtrack is not None: automation_info['automationtrack'] = 'Present' - # Lendo as tags de automationpattern (caso existam) + # Lendo as tags de automationpattern (caso existam) + # caso não existam, seta um valor default + # (assim acontece para, basicamente, todas as tags) for automationpattern in track.findall('./automationpattern'): automation_pattern_info = { 'name': automationpattern.attrib.get('name', 'N/A'), diff --git a/src/dtd/mmp.md b/src/dtd/mmp.md new file mode 100644 index 0000000..97cbd99 --- /dev/null +++ b/src/dtd/mmp.md @@ -0,0 +1,179 @@ +# Documentação do Arquivo .mmp (LMMS) + +## `` +- **Ocorrências**: 1 +- **Atributos**: + - `version` (**Obrigatório**) — Exemplos: `1.0` + - `type` (**Obrigatório**) — Exemplos: `song` + - `creator` (**Obrigatório**) — Exemplos: `LMMS` + - `creatorversion` (**Obrigatório**) — Exemplos: `1.2.2` + +## `` +- **Ocorrências**: 1 +- **Atributos**: + - `mastervol` (**Obrigatório**) — Exemplos: `100` + - `timesig_denominator` (**Obrigatório**) — Exemplos: `4` + - `bpm` (**Obrigatório**) — Exemplos: `140` + - `timesig_numerator` (**Obrigatório**) — Exemplos: `4` + - `masterpitch` (**Obrigatório**) — Exemplos: `0` + +## `` +- **Ocorrências**: 1 +- *(Sem atributos)* + +## `` +- **Ocorrências**: 2 +- **Atributos**: + - `width` (**Obrigatório**) — Exemplos: `700`, `600` + - `y` (**Obrigatório**) — Exemplos: `50`, `5` + - `minimized` (**Obrigatório**) — Exemplos: `0` + - `type` (**Obrigatório**) — Exemplos: `bbtrackcontainer`, `song` + - `visible` (**Obrigatório**) — Exemplos: `1` + - `x` (**Obrigatório**) — Exemplos: `266`, `5` + - `maximized` (**Obrigatório**) — Exemplos: `0` + - `height` (**Obrigatório**) — Exemplos: `400`, `300` + +## `` +- **Ocorrências**: 7 +- **Atributos**: + - `type` (**Obrigatório**) — Exemplos: `5`, `0`, `1` + - `solo` (**Obrigatório**) — Exemplos: `0` + - `muted` (**Obrigatório**) — Exemplos: `0` + - `name` (**Obrigatório**) — Exemplos: `Automation track`, `Kicker` + +## `` +- **Ocorrências**: 3 +- **Atributos**: + - `vol` (**Obrigatório**) — Exemplos: `100` + - `pitch` (**Obrigatório**) — Exemplos: `0` + - `fxch` (**Obrigatório**) — Exemplos: `0` + - `pitchrange` (**Obrigatório**) — Exemplos: `1` + - `basenote` (**Obrigatório**) — Exemplos: `57` + - `usemasterpitch` (**Obrigatório**) — Exemplos: `1` + - `pan` (**Obrigatório**) — Exemplos: `0` + +## `` +- **Ocorrências**: 3 +- **Atributos**: + - `name` (**Obrigatório**) — Exemplos: `audiofileprocessor`, `kicker`, `tripleoscillator` + +## `` +- **Ocorrências**: 1 +- **Atributos**: + - Todos são **Obrigatórios** neste contexto (pois há uma única ocorrência) + - Exemplos incluem: + - `wavetype0`: `0`, `userwavefile0`: ``, `vol0`: `33`, `pan0`: `0`, `phoffset0`: `0`, etc. + +## ``, ``, ``, `` +- **Ocorrências**: 3 (cada) +- **Atributos**: + - Todos **Obrigatórios** + - Exemplos: `att`: `0`, `dec`: `0.5`, `rel`: `0.1`, `lspd`: `0.1`, `userwavefile`: `` + +## `` +- **Ocorrências**: 3 +- **Atributos**: + - `chordrange` (**Obrigatório**) — Exemplos: `1` + - `chord-enabled` (**Obrigatório**) — Exemplos: `0` + - `chord` (**Obrigatório**) — Exemplos: `0` + +## `` +- **Ocorrências**: 3 +- **Atributos**: + - Todos **Obrigatórios** + - Exemplos: `arp`: `0`, `arpdir`: `0`, `arpgate`: `100` + +## `` +- **Ocorrências**: 3 +- **Atributos**: + - Todos **Obrigatórios** + - Exemplos: `inputchannel`: `0`, `outputchannel`: `1` + +## `` +- **Ocorrências**: 5 +- **Atributos**: + - `enabled` (**Obrigatório**) — Exemplos: `0` + - `numofeffects` (**Obrigatório**) — Exemplos: `0` + +## `` +- **Ocorrências**: 1 +- **Atributos**: + - `vol`, `pan` (**Obrigatórios**) — Exemplos: `100`, `0` + +## `` +- **Ocorrências**: 1 +- *(Sem atributos)* + +## `` +- **Ocorrências**: 1 +- **Atributos**: + - Todos são **Obrigatórios** + - Exemplos: `decay`: `440`, `dist`: `0.8`, `startfreq`: `150` + +## `` +- **Ocorrências**: 2 +- **Atributos**: + - Todos **Obrigatórios** + - Exemplos: `steps`: `16`, `name`: `Kicker`, `clap04.ogg` + +## `` +- **Ocorrências**: 5 +- **Atributos**: + - Todos **Obrigatórios** + - Exemplos: `key`: `57`, `vol`: `100`, `len`: `-192` + +## `` +- **Ocorrências**: 1 +- **Atributos**: + - Todos **Obrigatórios** + - Exemplos: `src`: `drums/clap04.ogg`, `looped`: `0`, `reversed`: `0` + +## `` +- **Ocorrências**: 1 +- **Atributos**: + - Todos **Obrigatórios** + - Exemplos: `name`: ``, `pos`: `0`, `len`: `192` + +## `` +- **Ocorrências**: 2 +- *(Sem atributos)* + +## `` +- **Ocorrências**: 5 +- **Atributos**: + - Todos **Obrigatórios** + - Exemplos: `name`: `Tempo`, `len`: `192`, `prog`: `0` + +## `` +- **Ocorrências**: 1 +- **Atributos**: + - Todos **Obrigatórios** + - Exemplos: `width`: `543`, `height`: `333`, `visible`: `1` + +## `` +- **Ocorrências**: 1 +- **Atributos**: + - Todos **Obrigatórios** + - Exemplos: `name`: `Master`, `volume`: `1` + +## `` +- **Ocorrências**: 1 +- **Atributos**: + - Todos **Obrigatórios** + - Exemplos: `width`: `350`, `visible`: `1` + +## ``, ``, `` +- **Ocorrências**: 1 (cada) +- **Atributos**: + - Todos **Obrigatórios** + - Exemplos: `visible`: `0`, `width`: `860` + +## `` +- **Ocorrências**: 1 +- **Atributos**: + - Todos **Obrigatórios** + - Exemplos: `lp0pos`: `0`, `lp1pos`: `192` + +## `` +- **Ocorrências**: 1 +- *(Sem atributos)* \ No newline at end of file diff --git a/src/dtd/mmp.xsd b/src/dtd/mmp.xsd new file mode 100644 index 0000000..555f270 --- /dev/null +++ b/src/dtd/mmp.xsd @@ -0,0 +1,512 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file