From f67943c01002ad0d625224db14d1d5b12249cb35 Mon Sep 17 00:00:00 2001 From: mwinter Date: Sun, 9 Apr 2023 17:20:10 +0200 Subject: [PATCH] initial commit of seeds and ledgers development code --- lilypond/includes/part_I.ly | 481 ++++ lilypond/includes/part_II.ly | 481 ++++ lilypond/includes/part_III.ly | 481 ++++ lilypond/includes/part_IV.ly | 481 ++++ lilypond/score_template.ly | 177 ++ lilypond/score_template.midi | Bin 0 -> 1565 bytes lilypond/score_template.pdf | Bin 0 -> 611695 bytes .../fragments/dur_probs_panel.json | 159 ++ open_stage_control/fragments/env.json | 372 +++ .../fragments/range_slider.json | 228 ++ open_stage_control/fragments/slider.json | 186 ++ open_stage_control/modules/custom_module.js | 277 ++ open_stage_control/seeds_and_ledgers_gui.json | 2529 +++++++++++++++++ .../seeds_and_ledgers_gui_bak.json | 2443 ++++++++++++++++ resources/314491/314491_code.scd | 581 ++++ resources/314491/314491_gui_session.json | 1400 +++++++++ resources/314491/314491_gui_state.state | 177 ++ resources/314491/314491_music.json | 75 + resources/46b6952a/46b6952a_code.scd | 719 +++++ resources/46b6952a/46b6952a_gui_state.json | 1359 +++++++++ resources/46b6952a/46b6952a_mus_model.json | 57 + resources/4c01589b/4c01589b_code.scd | 718 +++++ resources/4c01589b/4c01589b_gui_state.json | 1359 +++++++++ resources/4c01589b/4c01589b_mus_model.json | 85 + resources/55930f4d/55930f4d_code.scd | 757 +++++ resources/55930f4d/55930f4d_mus_model.json | 105 + resources/5cf1e9ab/5cf1e9ab_code.scd | 723 +++++ resources/5cf1e9ab/5cf1e9ab_mus_model.json | 41 + resources/5e947063/5e947063_code.scd | 716 +++++ resources/5e947063/5e947063_mus_model.json | 48 + resources/628d5c8b/628d5c8b_code.scd | 741 +++++ resources/628d5c8b/628d5c8b_mus_model.json | 56 + resources/62b894e8/62b894e8_code.scd | 735 +++++ resources/62b894e8/62b894e8_mus_model.json | 91 + resources/640eeed3/640eeed3_code.scd | 716 +++++ resources/640eeed3/640eeed3_mus_model.json | 38 + resources/7aa8c429/7aa8c429_code.scd | 734 +++++ resources/7aa8c429/7aa8c429_mus_model.json | 46 + resources/7ac10d34/7ac10d34_code.scd | 719 +++++ resources/7ac10d34/7ac10d34_gui_state.json | 1359 +++++++++ resources/7ac10d34/7ac10d34_mus_model.json | 59 + resources/7e170ef8/7e170ef8_code.scd | 718 +++++ resources/7e170ef8/7e170ef8_gui_state.json | 1359 +++++++++ resources/7e170ef8/7e170ef8_mus_model.json | 79 + resources/7ead41c3/7ead41c3_code.scd | 734 +++++ resources/7ead41c3/7ead41c3_mus_model.json | 77 + resources/piece_ledger.json | 17 + resources/piece_ledger.json_bak | 16 + resources/piece_ledger.json_bak_bak | 17 + resources/tmp/tmp_gui_state.json.json | 603 ++++ resources/tmp/tmp_mus_model.json | 113 + supercollider/seeds_and_ledgers_main.scd | 757 +++++ supercollider/seeds_and_ledgers_main_dict.scd | 727 +++++ .../seeds_and_ledgers_transcriber.scd | 324 +++ 54 files changed, 28050 insertions(+) create mode 100644 lilypond/includes/part_I.ly create mode 100644 lilypond/includes/part_II.ly create mode 100644 lilypond/includes/part_III.ly create mode 100644 lilypond/includes/part_IV.ly create mode 100644 lilypond/score_template.ly create mode 100644 lilypond/score_template.midi create mode 100644 lilypond/score_template.pdf create mode 100644 open_stage_control/fragments/dur_probs_panel.json create mode 100644 open_stage_control/fragments/env.json create mode 100644 open_stage_control/fragments/range_slider.json create mode 100644 open_stage_control/fragments/slider.json create mode 100644 open_stage_control/modules/custom_module.js create mode 100644 open_stage_control/seeds_and_ledgers_gui.json create mode 100644 open_stage_control/seeds_and_ledgers_gui_bak.json create mode 100644 resources/314491/314491_code.scd create mode 100644 resources/314491/314491_gui_session.json create mode 100644 resources/314491/314491_gui_state.state create mode 100644 resources/314491/314491_music.json create mode 100644 resources/46b6952a/46b6952a_code.scd create mode 100644 resources/46b6952a/46b6952a_gui_state.json create mode 100644 resources/46b6952a/46b6952a_mus_model.json create mode 100644 resources/4c01589b/4c01589b_code.scd create mode 100644 resources/4c01589b/4c01589b_gui_state.json create mode 100644 resources/4c01589b/4c01589b_mus_model.json create mode 100644 resources/55930f4d/55930f4d_code.scd create mode 100644 resources/55930f4d/55930f4d_mus_model.json create mode 100644 resources/5cf1e9ab/5cf1e9ab_code.scd create mode 100644 resources/5cf1e9ab/5cf1e9ab_mus_model.json create mode 100644 resources/5e947063/5e947063_code.scd create mode 100644 resources/5e947063/5e947063_mus_model.json create mode 100644 resources/628d5c8b/628d5c8b_code.scd create mode 100644 resources/628d5c8b/628d5c8b_mus_model.json create mode 100644 resources/62b894e8/62b894e8_code.scd create mode 100644 resources/62b894e8/62b894e8_mus_model.json create mode 100644 resources/640eeed3/640eeed3_code.scd create mode 100644 resources/640eeed3/640eeed3_mus_model.json create mode 100644 resources/7aa8c429/7aa8c429_code.scd create mode 100644 resources/7aa8c429/7aa8c429_mus_model.json create mode 100644 resources/7ac10d34/7ac10d34_code.scd create mode 100644 resources/7ac10d34/7ac10d34_gui_state.json create mode 100644 resources/7ac10d34/7ac10d34_mus_model.json create mode 100644 resources/7e170ef8/7e170ef8_code.scd create mode 100644 resources/7e170ef8/7e170ef8_gui_state.json create mode 100644 resources/7e170ef8/7e170ef8_mus_model.json create mode 100644 resources/7ead41c3/7ead41c3_code.scd create mode 100644 resources/7ead41c3/7ead41c3_mus_model.json create mode 100644 resources/piece_ledger.json create mode 100644 resources/piece_ledger.json_bak create mode 100644 resources/piece_ledger.json_bak_bak create mode 100644 resources/tmp/tmp_gui_state.json.json create mode 100644 resources/tmp/tmp_mus_model.json create mode 100644 supercollider/seeds_and_ledgers_main.scd create mode 100644 supercollider/seeds_and_ledgers_main_dict.scd create mode 100644 supercollider/seeds_and_ledgers_transcriber.scd diff --git a/lilypond/includes/part_I.ly b/lilypond/includes/part_I.ly new file mode 100644 index 0000000..047248e --- /dev/null +++ b/lilypond/includes/part_I.ly @@ -0,0 +1,481 @@ +\new StaffGroup \with {\remove "System_start_delimiter_engraver"} +<< +\new Staff = "I" \with { +instrumentName = "I" +shortInstrumentName = "I" +midiInstrument = #"clarinet" + +} +<< + +{ +\set Score.markFormatter = #format-mark-box-numbers \tempo 2 = 60 + \numericTimeSignature \time 2/2 + \clef treble + +<< + { r1 } +>> + \bar "|" +<< + { r2 r16[ e'8.^\markup { \pad-markup #0.2 "-14"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "5/4" }}] ~ e'4 ~ } +>> + \bar "|" +<< + { e'1 ~ } +>> + \bar "|" +<< + { e'1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { e'1 ~ } +>> + \bar "|" +<< + { e'1 ~ } +>> + \bar "|" +<< + { e'4 ~ e'16[ r8.] r2 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \break \noPageBreak +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r2. d'4^\markup { \pad-markup #0.2 "-49"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "16/11" }} ~ } +>> + \bar "|" \pageBreak +<< + { d'1 ~ } +>> + \bar "|" +<< + { d'2 dis'4^\markup { \pad-markup #0.2 "+16"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "8/5" }} ~ dis'4 ~ } +>> + \bar "|" +<< + { dis'4 ~ dis'8[ f'8^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "7/4" }}] ~ f'2 ~ } +>> + \bar "|" +<< + { f'1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { f'1 ~ } +>> + \bar "|" +<< + { f'2 ~ f'16[ e'8.^\markup { \pad-markup #0.2 "+13"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "11/8" }}] ~ e'4 ~ } +>> + \bar "|" +<< + { e'1 ~ } +>> + \bar "|" +<< + { e'1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { e'4 ~ e'8.[ e'16^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "4/3" }}] ~ e'2 ~ } +>> + \bar "|" +<< + { e'8.[ fis'16^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "2/1" }}] ~ fis'2. ~ } +>> + \bar "|" +<< + { fis'1 ~ } +>> + \bar "|" +<< + { fis'1 ~ } +>> + \bar "|" \pageBreak +<< + { fis'2. ~ fis'8.[ r16] } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r4 r16[ gis'8.^\markup { \pad-markup #0.2 "-5"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "3/4" }}] ~ gis'2 ~ } +>> + \bar "|" +<< + { gis'1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { gis'1 ~ } +>> + \bar "|" +<< + { gis'1 ~ } +>> + \bar "|" +<< + { gis'4 fis'4^\markup { \pad-markup #0.2 "-9"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "2/3" }} ~ fis'2 ~ } +>> + \bar "|" +<< + { fis'1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { fis'1 ~ } +>> + \bar "|" +<< + { fis'2. ~ fis'8.[ r16] } +>> + \bar "|" +<< + { r2. r8[ gis'8^\markup { \pad-markup #0.2 "-5"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "3/4" }}] ~ } +>> + \bar "|" +<< + { gis'1 ~ } +>> + \bar "|" \pageBreak +<< + { gis'1 ~ } +>> + \bar "|" +<< + { gis'1 ~ } +>> + \bar "|" +<< + { gis'4 ~ gis'16[ a'8.^\markup { \pad-markup #0.2 "+33"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "13/16" }}] ~ a'2 ~ } +>> + \bar "|" +<< + { a'2 ~ a'8[ r8] r4 } +>> + \bar "|" \break \noPageBreak +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r8.[ ais'16^\markup { \pad-markup #0.2 "-28"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "2/1" }}] ~ ais'2. ~ } +>> + \bar "|" \break \noPageBreak +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" \pageBreak +<< + { ais'2. r4 } +>> + \bar "|" +<< + { r8.[ ais'16^\markup { \pad-markup #0.2 "-28"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "100/100" }}] ~ ais'2. ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" \pageBreak +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'8.[ r16] r2. } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \break \noPageBreak +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \break \noPageBreak +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \pageBreak +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \break \noPageBreak +<< + { r1 } +>> + \bar "|" +<< + { r2 ais'4^\markup { \pad-markup #0.2 "-28"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "11/4" }} ~ ais'4 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" \pageBreak +<< + { ais'16[ r8.] r2. } +>> + \bar "|" +<< + { r2 r8[ ais'8^\markup { \pad-markup #0.2 "-28"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "100/100" }}] ~ ais'4 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'2. ~ ais'8[ r8] } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \break \noPageBreak +<< + { r1 } +>> + \bar "|" +<< + { r4 ais'4^\markup { \pad-markup #0.2 "-28"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "13/4" }} ~ ais'2 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" \pageBreak +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'16[ r8.] r2. } +>> + \bar "|" \break \noPageBreak +<< + { r1 } +>> + \bar "|" +<< + { r8.[ a'16^\markup { \pad-markup #0.2 "-22"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "32/13" }}] ~ a'2 ~ a'8.[ g'16^\markup { \pad-markup #0.2 "+49"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "16/7" }}] ~ } +>> + \bar "|" +<< + { g'1 ~ } +>> + \bar "|" +<< + { g'1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { g'4 ais'4^\markup { \pad-markup #0.2 "+16"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "8/3" }} ~ ais'2 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" \pageBreak +<< + { ais'8[ r8] r8[ ais'8^\markup { \pad-markup #0.2 "+16"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "100/100" }}] ~ ais'2 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { ais'1 ~ } +>> + \bar "|" +<< + { ais'2 ~ ais'16[ r8.] r4 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 \fermata }>> \bar "|." +} + +>> +>> \ No newline at end of file diff --git a/lilypond/includes/part_II.ly b/lilypond/includes/part_II.ly new file mode 100644 index 0000000..8234a07 --- /dev/null +++ b/lilypond/includes/part_II.ly @@ -0,0 +1,481 @@ +\new StaffGroup \with {\remove "System_start_delimiter_engraver"} +<< +\new Staff = "II" \with { +instrumentName = "II" +shortInstrumentName = "II" +midiInstrument = #"clarinet" + +} +<< + +{ +\set Score.markFormatter = #format-mark-box-numbers \tempo 2 = 60 + \numericTimeSignature \time 2/2 + \clef treble + +<< + { r1 } +>> + \bar "|" +<< + { r8[ fis'8^\markup { \pad-markup #0.2 "-49"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "11/8" }}] ~ fis'2. ~ } +>> + \bar "|" +<< + { fis'2 ~ fis'8[ e'8^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "16/13" }}] ~ e'4 ~ } +>> + \bar "|" +<< + { e'2 f'4^\markup { \pad-markup #0.2 "-2"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "4/3" }} ~ f'4 ~ } +>> + \bar "|" \break \noPageBreak +<< + { f'1 ~ } +>> + \bar "|" +<< + { f'4 g'4^\markup { \pad-markup #0.2 "+2"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "2/1" }} ~ g'2 ~ } +>> + \bar "|" +<< + { g'1 ~ } +>> + \bar "|" +<< + { g'2. r4 } +>> + \bar "|" \break \noPageBreak +<< + { r4 r8[ f'8^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "7/4" }}] ~ f'2 ~ } +>> + \bar "|" +<< + { f'1 ~ } +>> + \bar "|" +<< + { f'8.[ g'16^\markup { \pad-markup #0.2 "+2"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "2/1" }}] ~ g'2. } +>> + \bar "|" +<< + { a'4^\markup { \pad-markup #0.2 "+33"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "16/7" }} ~ a'2. ~ } +>> + \bar "|" \pageBreak +<< + { a'2 ~ a'8.[ r16] r4 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \break \noPageBreak +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r4 r8.[ b'16^\markup { \pad-markup #0.2 "-39"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "2/1" }}] ~ b'2 ~ } +>> + \bar "|" +<< + { b'1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { b'1 ~ } +>> + \bar "|" +<< + { b'1 } +>> + \bar "|" +<< + { d''4^\markup { \pad-markup #0.2 "+21"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "32/13" }} ~ d''2. ~ } +>> + \bar "|" +<< + { d''4 ~ d''16[ cis''8.^\markup { \pad-markup #0.2 "-7"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "16/7" }}] ~ cis''2 ~ } +>> + \bar "|" \pageBreak +<< + { cis''1 ~ } +>> + \bar "|" +<< + { cis''4 ~ cis''8[ r8] r2 } +>> + \bar "|" +<< + { cis''4^\markup { \pad-markup #0.2 "-7"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "100/100" }} ~ cis''2. ~ } +>> + \bar "|" +<< + { cis''1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { cis''1 ~ } +>> + \bar "|" +<< + { cis''1 ~ } +>> + \bar "|" +<< + { cis''1 ~ } +>> + \bar "|" +<< + { cis''1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { cis''2. ~ cis''16[ r8.] } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r4 r16[ cis''8.^\markup { \pad-markup #0.2 "-7"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "100/100" }}] ~ cis''2 ~ } +>> + \bar "|" +<< + { cis''1 ~ } +>> + \bar "|" \pageBreak +<< + { cis''1 ~ } +>> + \bar "|" +<< + { cis''1 ~ } +>> + \bar "|" +<< + { cis''1 ~ } +>> + \bar "|" +<< + { cis''1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { cis''1 ~ } +>> + \bar "|" +<< + { cis''1 ~ } +>> + \bar "|" +<< + { cis''2 ~ cis''8.[ d''16^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "5/2" }}] ~ d''4 ~ } +>> + \bar "|" +<< + { d''1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { d''2 dis''4^\markup { \pad-markup #0.2 "+24"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "11/4" }} ~ dis''4 ~ } +>> + \bar "|" +<< + { dis''4 ~ dis''8[ fis''8^\markup { \pad-markup #0.2 "-14"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "16/5" }}] ~ fis''2 ~ } +>> + \bar "|" +<< + { fis''4 f''4^\markup { \pad-markup #0.2 "-26"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "3/1" }} ~ f''2 ~ } +>> + \bar "|" +<< + { f''1 ~ } +>> + \bar "|" \pageBreak +<< + { f''2. ~ f''8[ r8] } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r4 r16[ e''8.^\markup { \pad-markup #0.2 "+21"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "16/11" }}] ~ e''2 } +>> + \bar "|" +<< + { dis''4^\markup { \pad-markup #0.2 "+24"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "11/8" }} ~ dis''2. ~ } +>> + \bar "|" \break \noPageBreak +<< + { dis''1 ~ } +>> + \bar "|" +<< + { dis''8.[ fis''16^\markup { \pad-markup #0.2 "-14"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "8/5" }}] ~ fis''2. ~ } +>> + \bar "|" +<< + { fis''1 ~ } +>> + \bar "|" +<< + { fis''1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { fis''1 ~ } +>> + \bar "|" +<< + { fis''1 ~ } +>> + \bar "|" +<< + { fis''1 ~ } +>> + \bar "|" +<< + { fis''1 ~ } +>> + \bar "|" \pageBreak +<< + { fis''1 ~ } +>> + \bar "|" +<< + { fis''2. gis''4^\markup { \pad-markup #0.2 "+7"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "4/1" }} ~ } +>> + \bar "|" +<< + { gis''1 ~ } +>> + \bar "|" +<< + { gis''4 ~ gis''16[ a''8.^\markup { \pad-markup #0.2 "+19"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "16/3" }}] ~ a''2 ~ } +>> + \bar "|" \break \noPageBreak +<< + { a''2. ~ a''16[ ais''8.^\markup { \pad-markup #0.2 "-28"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "11/2" }}] ~ } +>> + \bar "|" +<< + { ais''1 ~ } +>> + \bar "|" +<< + { ais''1 ~ } +>> + \bar "|" +<< + { ais''8.[ gis''16^\markup { \pad-markup #0.2 "-19"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "64/13" }}] ~ gis''2. ~ } +>> + \bar "|" \break \noPageBreak +<< + { gis''4 gis''4^\markup { \pad-markup #0.2 "+7"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "5/1" }} ~ gis''2 ~ } +>> + \bar "|" +<< + { gis''4 r2. } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r4 r16[ g''8.^\markup { \pad-markup #0.2 "-48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "4/1" }}] ~ g''2 ~ } +>> + \bar "|" \pageBreak +<< + { g''2 ~ g''8.[ e''16^\markup { \pad-markup #0.2 "+21"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "4/1" }}] ~ e''4 ~ } +>> + \bar "|" +<< + { e''2 ~ e''8[ d''8^\markup { \pad-markup #0.2 "-10"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "7/2" }}] ~ d''4 ~ } +>> + \bar "|" +<< + { d''1 ~ } +>> + \bar "|" +<< + { d''1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { d''16[ r8.] r2. } +>> + \bar "|" +<< + { r2. r8[ d''8^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "5/4" }}] ~ } +>> + \bar "|" +<< + { d''2 dis''4^\markup { \pad-markup #0.2 "+24"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "11/8" }} ~ dis''4 ~ } +>> + \bar "|" +<< + { dis''2 ~ dis''8[ e''8^\markup { \pad-markup #0.2 "+21"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "4/1" }}] ~ e''4 ~ } +>> + \bar "|" \break \noPageBreak +<< + { e''2. ~ e''8[ f''8^\markup { \pad-markup #0.2 "-26"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "3/2" }}] ~ } +>> + \bar "|" +<< + { f''1 ~ } +>> + \bar "|" +<< + { f''4 fis''4^\markup { \pad-markup #0.2 "-14"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "8/5" }} ~ fis''2 ~ } +>> + \bar "|" +<< + { fis''8[ g''8^\markup { \pad-markup #0.2 "-48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "32/7" }}] ~ g''2. ~ } +>> + \bar "|" \pageBreak +<< + { g''2 ~ g''16[ r8.] r4 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r8.[ g''16^\markup { \pad-markup #0.2 "+41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "4/1" }}] ~ g''2. ~ } +>> + \bar "|" +<< + { g''2 ~ g''8[ fis''8^\markup { \pad-markup #0.2 "-14"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "8/5" }}] ~ fis''4 ~ } +>> + \bar "|" \break \noPageBreak +<< + { fis''2 ~ fis''8[ dis''8^\markup { \pad-markup #0.2 "+24"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "11/8" }}] ~ dis''4 ~ } +>> + \bar "|" +<< + { dis''4 ~ dis''8.[ e''16^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "32/7" }}] ~ e''2 ~ } +>> + \bar "|" +<< + { e''2. ~ e''8[ cis''8^\markup { \pad-markup #0.2 "+32"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "4/1" }}] ~ } +>> + \bar "|" +<< + { cis''1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { cis''2 b'4^\markup { \pad-markup #0.2 "+1"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "7/2" }} ~ b'4 ~ } +>> + \bar "|" +<< + { b'1 ~ } +>> + \bar "|" +<< + { b'1 ~ } +>> + \bar "|" +<< + { b'1 ~ } +>> + \bar "|" \pageBreak +<< + { b'1 ~ } +>> + \bar "|" +<< + { b'1 ~ } +>> + \bar "|" +<< + { b'1 ~ } +>> + \bar "|" +<< + { b'4 ~ b'8.[ r16] r2 } +>> + \bar "|" \break \noPageBreak +<< + { r2 r16[ cis''8.^\markup { \pad-markup #0.2 "+32"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "16/5" }}] ~ cis''4 ~ } +>> + \bar "|" +<< + { cis''1 ~ } +>> + \bar "|" +<< + { cis''2 ~ cis''8.[ dis''16^\markup { \pad-markup #0.2 "-13"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "7/2" }}] ~ dis''4 ~ } +>> + \bar "|" +<< + { dis''1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { dis''2 ~ dis''16[ r8.] r4 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \pageBreak +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \break \noPageBreak +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 \fermata }>> \bar "|." +} + +>> +>> \ No newline at end of file diff --git a/lilypond/includes/part_III.ly b/lilypond/includes/part_III.ly new file mode 100644 index 0000000..abf62f9 --- /dev/null +++ b/lilypond/includes/part_III.ly @@ -0,0 +1,481 @@ +\new StaffGroup \with {\remove "System_start_delimiter_engraver"} +<< +\new Staff = "III" \with { +instrumentName = "III" +shortInstrumentName = "III" +midiInstrument = #"clarinet" + +} +<< + +{ +\set Score.markFormatter = #format-mark-box-numbers \tempo 2 = 60 + \numericTimeSignature \time 2/2 + \clef alto + +<< + { c'4^\markup { \pad-markup #0.2 "+0"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "nil"\normal-size-super "1/1" }} ~ c'2. ~ } +>> + \bar "|" +<< + { c'1 ~ } +>> + \bar "|" +<< + { c'1 ~ } +>> + \bar "|" +<< + { c'1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { c'1 ~ } +>> + \bar "|" +<< + { c'1 ~ } +>> + \bar "|" +<< + { c'2 ~ c'8.[ r16] r4 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \break \noPageBreak +<< + { r2. r16[ cis'8.^\markup { \pad-markup #0.2 "-47"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "11/8" }}] ~ } +>> + \bar "|" +<< + { cis'1 ~ } +>> + \bar "|" +<< + { cis'1 ~ } +>> + \bar "|" +<< + { cis'1 ~ } +>> + \bar "|" \pageBreak +<< + { cis'4 ~ cis'16[ b8.^\markup { \pad-markup #0.2 "-12"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "5/4" }}] ~ b2 ~ } +>> + \bar "|" +<< + { b1 ~ } +>> + \bar "|" +<< + { b1 ~ } +>> + \bar "|" +<< + { b2. a4^\markup { \pad-markup #0.2 "+33"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "8/7" }} ~ } +>> + \bar "|" \break \noPageBreak +<< + { a4 ~ a8[ b8^\markup { \pad-markup #0.2 "-39"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "16/13" }}] ~ b2 ~ } +>> + \bar "|" +<< + { b1 ~ } +>> + \bar "|" +<< + { b1 ~ } +>> + \bar "|" +<< + { b1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { b1 ~ } +>> + \bar "|" +<< + { b1 ~ } +>> + \bar "|" +<< + { b1 ~ } +>> + \bar "|" +<< + { b1 ~ } +>> + \bar "|" \pageBreak +<< + { b4 ~ b16[ r8.] r2 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r4 a4^\markup { \pad-markup #0.2 "+6"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "2/5" }} ~ a2 ~ } +>> + \bar "|" \break \noPageBreak +<< + { a4 ~ a8.[ fis16^\markup { \pad-markup #0.2 "+44"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "11/32" }}] ~ fis2 ~ } +>> + \bar "|" +<< + { fis1 ~ } +>> + \bar "|" +<< + { fis1 ~ } +>> + \bar "|" +<< + { fis1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { fis1 ~ } +>> + \bar "|" +<< + { fis4 ~ fis8[ r8] r2 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r2. a4^\markup { \pad-markup #0.2 "+6"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "2/5" }} ~ } +>> + \bar "|" \pageBreak +<< + { a2. ~ a8[ g8^\markup { \pad-markup #0.2 "+41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "4/11" }}] ~ } +>> + \bar "|" +<< + { g2 ~ g8[ dis8^\markup { \pad-markup #0.2 "+24"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "2/7" }}] ~ dis4 ~ } +>> + \bar "|" +<< + { dis1 ~ } +>> + \bar "|" +<< + { dis1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { dis1 ~ } +>> + \bar "|" +<< + { dis1 ~ } +>> + \bar "|" +<< + { dis1 ~ } +>> + \bar "|" +<< + { dis2. dis4^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "2/3" }} ~ } +>> + \bar "|" \break \noPageBreak +<< + { dis1 ~ } +>> + \bar "|" +<< + { dis1 ~ } +>> + \bar "|" +<< + { dis2. ~ dis8[ cis8^\markup { \pad-markup #0.2 "+32"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "8/13" }}] ~ } +>> + \bar "|" +<< + { cis2. ~ cis8[ r8] } +>> + \bar "|" \pageBreak +<< + { r1 } +>> + \bar "|" +<< + { r2. r16[ c8.^\markup { \pad-markup #0.2 "+4"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "2/7" }}] ~ } +>> + \bar "|" +<< + { c1 ~ } +>> + \bar "|" +<< + { c1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { c4 ~ c16[ dis8.^\markup { \pad-markup #0.2 "+24"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "1/4" }}] ~ dis2 ~ } +>> + \bar "|" +<< + { dis1 ~ } +>> + \bar "|" +<< + { dis8.[ d16^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "5/16" }}] ~ d2. } +>> + \bar "|" +<< + { dis4^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "1/3" }} ~ dis2. } +>> + \bar "|" \break \noPageBreak +<< + { c4^\markup { \pad-markup #0.2 "+4"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "2/7" }} ~ c2. ~ } +>> + \bar "|" +<< + { c4 c4^\markup { \pad-markup #0.2 "+35"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "2/11" }} ~ c2 ~ } +>> + \bar "|" +<< + { c2 ~ c16[ d8.^\markup { \pad-markup #0.2 "+27"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "13/64" }}] ~ d4 ~ } +>> + \bar "|" +<< + { d2 ~ d8[ dis8^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "1/3" }}] ~ dis4 ~ } +>> + \bar "|" \pageBreak +<< + { dis4 ~ dis16[ e8.^\markup { \pad-markup #0.2 "+21"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "4/11" }}] ~ e2 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { e1 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { e1 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" +<< + { e8[ r8] r4 r16[ e8.^\markup { \pad-markup #0.2 "+21"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "100/100" }}] ~ e4 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" \pageBreak +<< + { e1 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { e2. ~ e8.[ r16] } +>> + \bar "|" +<< + { r4 e4^\markup { \pad-markup #0.2 "+21"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "100/100" }} ~ e2 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { e1 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" +<< + { e1 ~ } +>> + \bar "|" \pageBreak +<< + { e1 ~ } +>> + \bar "|" +<< + { e8[ r8] r2. } +>> + \bar "|" +<< + { r2 r8[ cis8^\markup { \pad-markup #0.2 "+32"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "4/13" }}] ~ cis4 ~ } +>> + \bar "|" +<< + { cis1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { cis1 ~ } +>> + \bar "|" +<< + { cis1 ~ } +>> + \bar "|" +<< + { cis1 ~ } +>> + \bar "|" +<< + { cis1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { cis1 ~ } +>> + \bar "|" +<< + { cis2 ~ cis16[ f8.^\markup { \pad-markup #0.2 "-26"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "3/8" }}] ~ f4 ~ } +>> + \bar "|" +<< + { f4 ~ f8.[ dis16^\markup { \pad-markup #0.2 "-13"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "5/16" }}] ~ dis2 ~ } +>> + \bar "|" +<< + { dis8.[ fis16^\markup { \pad-markup #0.2 "+3"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "3/8" }}] ~ fis2. } +>> + \bar "|" \pageBreak +<< + { g4^\markup { \pad-markup #0.2 "+14"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "2/5" }} ~ g4 ~ g8.[ ais16^\markup { \pad-markup #0.2 "-28"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "1/2" }}] ~ ais4 ~ } +>> + \bar "|" +<< + { ais4 ~ ais16[ b8.^\markup { \pad-markup #0.2 "+1"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "1/2" }}] ~ b2 ~ } +>> + \bar "|" +<< + { b16[ cis'8.^\markup { \pad-markup #0.2 "+32"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "4/7" }}] ~ cis'2. ~ } +>> + \bar "|" +<< + { cis'2. ~ cis'8[ r8] } +>> + \bar "|" \break \noPageBreak +<< + { r1 } +>> + \bar "|" +<< + { d'4^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "13/8" }} ~ d'2. ~ } +>> + \bar "|" +<< + { d'1 ~ } +>> + \bar "|" +<< + { d'2 ~ d'8[ cis'8^\markup { \pad-markup #0.2 "+32"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "8/5" }}] ~ cis'4 ~ } +>> + \bar "|" \break \noPageBreak +<< + { cis'1 ~ } +>> + \bar "|" +<< + { cis'4 ~ cis'8[ d'8^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "13/8" }}] ~ d'2 ~ } +>> + \bar "|" +<< + { d'8[ c'8^\markup { \pad-markup #0.2 "-33"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "16/11" }}] ~ c'2. ~ } +>> + \bar "|" +<< + { c'8[ r8] r2. } +>> + \bar "|" \pageBreak +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \break \noPageBreak +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 \fermata }>> \bar "|." +} + +>> +>> \ No newline at end of file diff --git a/lilypond/includes/part_IV.ly b/lilypond/includes/part_IV.ly new file mode 100644 index 0000000..c0ce49b --- /dev/null +++ b/lilypond/includes/part_IV.ly @@ -0,0 +1,481 @@ +\new StaffGroup \with {\remove "System_start_delimiter_engraver"} +<< +\new Staff = "IV" \with { +instrumentName = "IV" +shortInstrumentName = "IV" +midiInstrument = #"clarinet" + +} +<< + +{ +\set Score.markFormatter = #format-mark-box-numbers \tempo 2 = 60 + \numericTimeSignature \time 2/2 + \clef bass + +<< + { r2 r8[ gis8^\markup { \pad-markup #0.2 "+14"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "4/5" }}] ~ gis4 ~ } +>> + \bar "|" +<< + { gis1 ~ } +>> + \bar "|" +<< + { gis1 ~ } +>> + \bar "|" +<< + { gis1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { gis2 ~ gis16[ g8.^\markup { \pad-markup #0.2 "+2"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "3/4" }}] ~ g4 ~ } +>> + \bar "|" +<< + { g1 ~ } +>> + \bar "|" +<< + { g1 ~ } +>> + \bar "|" +<< + { g8.[ r16] r2. } +>> + \bar "|" \break \noPageBreak +<< + { r8.[ g16^\markup { \pad-markup #0.2 "+2"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "1/1" }}] ~ g2. ~ } +>> + \bar "|" +<< + { g1 ~ } +>> + \bar "|" +<< + { g1 ~ } +>> + \bar "|" +<< + { g1 ~ } +>> + \bar "|" \pageBreak +<< + { g1 ~ } +>> + \bar "|" +<< + { g1 ~ } +>> + \bar "|" +<< + { g1 ~ } +>> + \bar "|" +<< + { g1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { g1 ~ } +>> + \bar "|" +<< + { g2. ~ g8.[ f16^\markup { \pad-markup #0.2 "+10"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "8/11" }}] ~ } +>> + \bar "|" +<< + { f1 ~ } +>> + \bar "|" +<< + { f4 ~ f8[ fis8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "3/4" }}] ~ fis2 ~ } +>> + \bar "|" \break \noPageBreak +<< + { fis1 ~ } +>> + \bar "|" +<< + { fis1 ~ } +>> + \bar "|" +<< + { fis1 ~ } +>> + \bar "|" +<< + { fis1 ~ } +>> + \bar "|" \pageBreak +<< + { fis1 ~ } +>> + \bar "|" +<< + { fis2 ~ fis16[ r8.] r4 } +>> + \bar "|" +<< + { r2. r8[ gis8^\markup { \pad-markup #0.2 "-5"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "1/2" }}] ~ } +>> + \bar "|" +<< + { gis1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { gis1 ~ } +>> + \bar "|" +<< + { gis4 ~ gis8.[ a16^\markup { \pad-markup #0.2 "+33"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "13/32" }}] ~ a2 ~ } +>> + \bar "|" +<< + { a1 ~ } +>> + \bar "|" +<< + { a4 ~ a16[ g8.^\markup { \pad-markup #0.2 "+41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "4/11" }}] ~ g2 ~ } +>> + \bar "|" \break \noPageBreak +<< + { g8.[ fis16^\markup { \pad-markup #0.2 "-9"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "1/2" }}] ~ fis2. ~ } +>> + \bar "|" +<< + { fis2 ~ fis8[ r8] r4 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r8.[ gis16^\markup { \pad-markup #0.2 "-5"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "1/2" }}] ~ gis2. ~ } +>> + \bar "|" \pageBreak +<< + { gis1 ~ } +>> + \bar "|" +<< + { gis1 ~ } +>> + \bar "|" +<< + { gis1 ~ } +>> + \bar "|" +<< + { gis4 g2.^\markup { \pad-markup #0.2 "+41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "4/11" }} ~ } +>> + \bar "|" \break \noPageBreak +<< + { g2. ~ g8[ a8^\markup { \pad-markup #0.2 "+6"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super "2/5" }}] ~ } +>> + \bar "|" +<< + { a2 ~ a8.[ ais16^\markup { \pad-markup #0.2 "-28"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "16/11" }}] ~ ais4 ~ } +>> + \bar "|" +<< + { ais1 ~ } +>> + \bar "|" +<< + { ais1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { ais1 ~ } +>> + \bar "|" +<< + { ais1 ~ } +>> + \bar "|" +<< + { ais1 ~ } +>> + \bar "|" +<< + { ais1 ~ } +>> + \bar "|" \pageBreak +<< + { ais4 ~ ais16[ r8.] r2 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \break \noPageBreak +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \break \noPageBreak +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \pageBreak +<< + { r1 } +>> + \bar "|" +<< + { r8.[ gis16^\markup { \pad-markup #0.2 "+7"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "5/4" }}] ~ gis2. ~ } +>> + \bar "|" +<< + { gis1 ~ } +>> + \bar "|" +<< + { gis1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { gis16[ g8.^\markup { \pad-markup #0.2 "-48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "8/7" }}] ~ g2. ~ } +>> + \bar "|" +<< + { g2. ~ g8[ a8^\markup { \pad-markup #0.2 "+19"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "4/3" }}] ~ } +>> + \bar "|" +<< + { a1 ~ } +>> + \bar "|" +<< + { a1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { a1 ~ } +>> + \bar "|" +<< + { a2 r2 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r8[ g8^\markup { \pad-markup #0.2 "-48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "8/7" }}] ~ g2. ~ } +>> + \bar "|" \pageBreak +<< + { g1 ~ } +>> + \bar "|" +<< + { g1 ~ } +>> + \bar "|" +<< + { g2 ~ g8.[ ais16^\markup { \pad-markup #0.2 "-28"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "11/8" }}] ~ ais4 ~ } +>> + \bar "|" +<< + { ais1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { ais2 r2 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \break \noPageBreak +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \pageBreak +<< + { r1 } +>> + \bar "|" +<< + { r2. r8[ g8^\markup { \pad-markup #0.2 "+41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "7/16" }}] ~ } +>> + \bar "|" +<< + { g1 ~ } +>> + \bar "|" +<< + { g1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { g1 ~ } +>> + \bar "|" +<< + { g2 ~ g16[ fis8.^\markup { \pad-markup #0.2 "+30"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "4/3" }}] ~ fis4 ~ } +>> + \bar "|" +<< + { fis1 ~ } +>> + \bar "|" +<< + { fis2. ~ fis16[ f8.^\markup { \pad-markup #0.2 "+18"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super "5/4" }}] ~ } +>> + \bar "|" \break \noPageBreak +<< + { f1 ~ } +>> + \bar "|" +<< + { f2 ~ f8.[ r16] r4 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \pageBreak +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" \break \noPageBreak +<< + { r4 f2.^\markup { \pad-markup #0.2 "+18"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super "1/1" }} ~ } +>> + \bar "|" +<< + { f1 ~ } +>> + \bar "|" +<< + { f1 ~ } +>> + \bar "|" +<< + { f1 ~ } +>> + \bar "|" \break \noPageBreak +<< + { f1 ~ } +>> + \bar "|" +<< + { f1 ~ } +>> + \bar "|" +<< + { f1 ~ } +>> + \bar "|" +<< + { f2 ~ f8.[ r16] r4 } +>> + \bar "|" \pageBreak +<< + { r2 fis2^\markup { \pad-markup #0.2 "+30"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "2/5" }} ~ } +>> + \bar "|" +<< + { fis2. ~ fis8[ f8^\markup { \pad-markup #0.2 "-35"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "4/11" }}] ~ } +>> + \bar "|" +<< + { f1 ~ } +>> + \bar "|" +<< + { f4 f2.^\markup { \pad-markup #0.2 "+18"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "3/8" }} ~ } +>> + \bar "|" \break \noPageBreak +<< + { f8.[ dis16^\markup { \pad-markup #0.2 "+14"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super "1/3" }}] ~ dis2. ~ } +>> + \bar "|" +<< + { dis8.[ r16] r2. } +>> + \bar "|" +<< + { r1 } +>> + \bar "|" +<< + { r1 \fermata }>> \bar "|." +} + +>> +>> \ No newline at end of file diff --git a/lilypond/score_template.ly b/lilypond/score_template.ly new file mode 100644 index 0000000..822f3a6 --- /dev/null +++ b/lilypond/score_template.ly @@ -0,0 +1,177 @@ +\version "2.22.2" + +#(define (override-color-for-all-grobs color) + (lambda (context) + (let loop ((x all-grob-descriptions)) + (if (not (null? x)) + (let ((grob-name (caar x))) + (ly:context-pushpop-property context grob-name 'color color) + (loop (cdr x))))))) + + #(define-markup-command (relMark layout props mus) (ly:music?) + #:properties ((size -2)) + (interpret-markup layout props + #{ + \markup { + \score { + \new Staff { $mus } + \layout { + \context { + \Staff + \remove Time_signature_engraver + fontSize = #-2 + \hide Stem + \override TextScript.outside-staff-priority = ##f + \override StaffSymbol.staff-space = #(magstep -2) + \override StaffSymbol.thickness = #(magstep -2) + \override TextScript.self-alignment-X = #-0.4 + \override TextScript.staff-padding = #1 + } + \context { + \Score + proportionalNotationDuration = #(ly:make-moment 1/16) + \remove "Separating_line_group_engraver" + \override SpacingSpanner.strict-note-spacing = ##t + \override RehearsalMark.self-alignment-X = #-1 + \override RehearsalMark.Y-offset = #10 + \override RehearsalMark.X-offset = #10 + } + \context { + \Voice + \consists "Horizontal_bracket_engraver" + \override HorizontalBracket.direction = #UP + } + indent = 0 + line-width = 4\cm + } + } + } + #})) + + +\paper { + #(set-paper-size "a4" 'portrait) + top-margin = 1 \cm + bottom-margin = 1 \cm + left-margin = 2 \cm + ragged-bottom = ##t + + top-system-spacing = + #'((basic-distance . 15 ) + (minimum-distance . 15 ) + (padding . 0 ) + (stretchability . 0)) + + system-system-spacing = + #'((basic-distance . 35 ) + (minimum-distance . 35 ) + (padding . 0 ) + (stretchability . 0)) + + last-bottom-spacing = + #'((basic-distance . 10 ) + (minimum-distance . 10 ) + (padding . 0 ) + (stretchability . 0)) + + %systems-per-page = 3 + first-page-number = 1 + print-first-page-number = ##t + + print-page-number = ##t + oddHeaderMarkup = \markup { \fill-line { \line { \on-the-fly #not-first-page {\pad-markup #2 { \concat {\italic {"test"}}}}}}} + evenHeaderMarkup = \markup { \fill-line { \line { \on-the-fly #not-first-page {\pad-markup #2 { \concat {\italic {"test"}}}}}}} + oddFooterMarkup = \markup { \fill-line { + \concat { + "-" + \fontsize #1.5 + \on-the-fly #print-page-number-check-first + \fromproperty #'page:page-number-string + "-"}}} + evenFooterMarkup = \markup { \fill-line { + \concat { + "-" + \fontsize #1.5 + \on-the-fly #print-page-number-check-first + \fromproperty #'page:page-number-string + "-"}}} +} + +\header { + title = \markup { \italic {test}} + composer = \markup \right-column {"michael winter" "(berlin & mexico city; 2023)"} + %poet = "seed: xxx" + tagline = "" +} + +#(set-global-staff-size 11) + +\layout { + indent = 0.0\cm + line-width = 17.5\cm + ragged-last = ##f + ragged-right = ##f + + \context { + \Score + \override BarNumber.stencil = #(make-stencil-circler 0.1 0.25 ly:text-interface::print) + \override Stem.stemlet-length = #0.75 + proportionalNotationDuration = #(ly:make-moment 1/16) + \remove "Separating_line_group_engraver" + \override RehearsalMark.self-alignment-X = #-1 + \override RehearsalMark.Y-offset = #10 + \override RehearsalMark.X-offset = #-8 + %\override RehearsalMark.outside-staff-priority = #0 + } + \context { + \Staff + + \override VerticalAxisGroup.staff-staff-spacing = + #'((basic-distance . 20 ) + (minimum-distance . 20 ) + (padding . 0 ) + (stretchability . 0)) + + \override VerticalAxisGroup.default-staff-staff-spacing = + #'((basic-distance . 20 ) + (minimum-distance . 20 ) + (padding . 0 ) + (stretchability . 0)) + \override TextScript.staff-padding = #2 + \override TextScript.self-alignment-X = #0 + } + \context { + \StaffGroup + \name "SemiStaffGroup" + \consists "Span_bar_engraver" + \override SpanBar.stencil = + #(lambda (grob) + (if (string=? (ly:grob-property grob 'glyph-name) "|") + (set! (ly:grob-property grob 'glyph-name) "")) + (ly:span-bar::print grob)) + } + \context { + \Score + \accepts SemiStaffGroup + } +} + +\midi { } + + +\score{ +\new Score + << + \new SemiStaffGroup { + << + \include "includes/part_I.ly" + \include "includes/part_II.ly" + \include "includes/part_III.ly" + \include "includes/part_IV.ly" + >> + } + >> + + \layout{} + \midi{} +} diff --git a/lilypond/score_template.midi b/lilypond/score_template.midi new file mode 100644 index 0000000000000000000000000000000000000000..9e56cb45461bd68400fde07e1bc29bb759ed985e GIT binary patch literal 1565 zcmYk5&2N-d6vofcs<`zJFn7bWw5e^UMM&E@bD3%T(gX}9Xk5Monn)m!)Nb543kxmN z_Wb}_Y^YW-Mm8GbN8E{q7^9-$V?o@wa-oR<|AFy$?pxZK+?+h`bIy6r$Gvmx#G9u@ z7eickexQ?&RE=^Rx3my5z84 z!H6Vvz37vA04=@%le&rlG_(~bjlgUa%%t9mab+0&!-EzK{bERx$dn?$w4yW}^6uaV zG<300s_R3m*34rHZ(wllwBoI>hpFjmoYVknK!sLodKm-dP0E6*ddVf#0G50Jsy|zF zYSCyH(ezqG!&JpY^u4D_2$;|7rv<3#x}_z^DJmvj(`$aa6^7CfO}QfNdI1``#fZ2X z`o0G=A7S-xgSp?mj^kWM*9`Y@JF?SpACgY6#B@ULyVRqRBA?c2Caud82fAZO(uQuv zDTUH0mXJ;Xrdd$Rs?*2-%ZK^b!DJx_1J%%FAJQgu$*0`MZrTwOIue*mmS$PaTaL8L zR`**8b*I$ia7NZsQKf~7{Ac2KG5G45d!n0P`Lt>?usw#^h{G^7U2`cHf@=!{sM##W zC^wt3Sb}N6Cig5KaLf*!4?=~egOplYp}7?_ zzl_nmR%nhJ7?(xK#`QNt#E$D@LklsedBtEWz@Nle3@-unO~=FeCp?_j$K;2|PRD!; zaeh!&Tz*g_KSba8A;2iT<)eTDx`+wP)fnbiXjTw>qk7!~HsgHA@`i{S(M?RqL(=kI z)>TYk00)G?VWWnjhWNLKv_aOC55nxYD*Bh?6_^qI-37&Aiy4+bq4i@Qd=(S2pi$n< zcDrj&%YGeGHnRpESOZ_cYZh+H)u?+7Tpc#=aLT) z)MthJ0Q+^t<@*6Wywbb}u#e}K@8fahy|%;N5WVC>bg!ajOb?eDqWd%{T>Yllk86N8 k9cuLJXAb5@hfrA;G5`Po literal 0 HcmV?d00001 diff --git a/lilypond/score_template.pdf b/lilypond/score_template.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7b0bd5a3677beca7bb25a51f9abc3f6c4abcea03 GIT binary patch literal 611695 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℞gM+b!jJkqeCZs;&B22egweEp^;OVhF>)S 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 &c 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

xrIXRlgh<@0VnX0R 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�qND!a%Qm{ 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 jy~P!^TDPt>w7RgWdSq4cfLf$(5Z|@VI;%ssj \n locals.eucDistance([x, y], a) < locals.eucDistance([x, y], b) ? a : b));\n}\n\nlocals.cIndex = 1\nlocals.cDist = 0\n\nsetVar(this, 'reset', function() {\n set(getProp(\"parent\", \"id\") + \"_size\", 3)\n var val = []\n val.length = 64; \n val.fill(0);\n val[0] = [0.0, 0.5]\n val[1] = [0.5, 0.5]\n val[2] = [1.0, 0.5]\n set(getProp(\"parent\", \"id\") + '_canvas', val)\n})\n\n\nsetVar(this, 'update', function() {\n var limits = get(getProp(\"parent\", \"id\") + '_rslider')\n var vals = get(getProp(\"parent\", \"id\") + '_canvas')\n var size = get(getProp(\"parent\", \"id\") + '_size')\n set(getProp(\"parent\", \"id\") + \"_vals\", (limits).concat(vals.slice(0, size).flat()));\n var parentVariables = getProp('parent', 'variables')\n if (parentVariables.grandparent) {\n set(parentVariables.grandparent + '_vals', value)\n }\n})\n", + "onValue": "// apply limits\nfor(var i = 0; i < get(getProp(\"parent\", \"id\") + \"_size\"); i += 1) {\n if(typeof value[i] === 'string') {value[i] = JSON.parse(value[i])}\n value[i] = [Math.max(0, Math.min(1, value[i][0])), Math.max(0, Math.min(1, value[i][1]))]\n}\n\n// re-update widget value without retriggering script or sending message\nset(\"this\", value, {sync: true, send: false})\ngetVar('this', 'update')()", + "onTouch": "var lock = false\n\n// store normalized coordinates\nif (event.type == \"start\") {\n locals.x = event.offsetX / width\n locals.y = event.offsetY / height\n lock = true\n locals.cIndex = value.indexOf(locals.closest(value, locals.x, locals.y, get(getProp(\"parent\", \"id\") + \"_size\")))\n locals.cDist = locals.eucDistance([locals.x, locals.y], value[locals.cIndex])\n} else {\n // when the pointer is moving, increment coordinates\n // because offsetX and offsetY may not be relevant\n // if the pointer hovers a different widgets\n locals.x += event.movementX / width\n locals.y += event.movementY / height\n}\n\n\nif(lock && (locals.cDist > 0.1) && (locals.x >= 0) && (locals.y >= 0) && (locals.x <= 1) && (locals.y <= 1)) {\n value[get(getProp(\"parent\", \"id\") + \"_size\")] = [locals.x, 1 - locals.y]\n value.sort((a, b) => a[0] - b[0])\n locals.cIndex = value.indexOf(locals.closest(value, locals.x, locals.y, get(getProp(\"parent\", \"id\") + \"_size\")))\n set(getProp(\"parent\", \"id\") + '_size', get(getProp(\"parent\", \"id\") + \"_size\") + 1)\n} else {\n value[locals.cIndex] = [locals.x, 1 - locals.y]\n}\n\nvar min = get(getProp(\"parent\", \"id\") + \"_input_min\")\nvar max = get(getProp(\"parent\", \"id\") + \"_input_max\")\n\nif (event.type != \"stop\") {\n set(getProp(\"parent\", \"id\") + \"_mpos\", \"x: \" + ((locals.x * (max - min)) + min).toFixed(2) + \"\\ny: \" + (1 - locals.y).toFixed(2))\n} else {\n lock = false\n set(getProp(\"parent\", \"id\") + \"_mpos\", \"\")\n}\nset(\"this\", value)", + "onDraw": "//var size = get('@{parent.id}_size')\nfor(var i = 0; i < get(getProp(\"parent\", \"id\") + \"_size\"); i += 1) {\n ctx.fillStyle = cssVars.colorFill\n ctx.fillRect(value[i][0] * width - 2.5, (1 - value[i][1]) * height - 2.5, 5, 5)\n}\n\nctx.stroke();\nctx.strokeStyle = cssVars.colorFill\nctx.beginPath();\n\nfor(var i = 0; i < get(getProp(\"parent\", \"id\") + \"_size\"); i += 1) {\n if(i === 0){\n ctx.moveTo(value[i][0] * width, (1 - value[i][1]) * height)\n } else {\n ctx.lineTo(value[i][0] * width, (1 - value[i][1]) * height); // Draw a line to (150, 100)\n }\n}\n\nctx.stroke();", + "onResize": "" + }, + { + "type": "variable", + "lock": false, + "id": "@{parent.id}_size", + "comments": "", + "value": "", + "default": 3, + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "button", + "top": "auto", + "left": 0, + "lock": false, + "id": "@{parent.id}_flatten", + "visible": true, + "interaction": true, + "comments": "", + "width": 30, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": ":host {\n\n top: calc(100% - 30rem);\n\n}", + "colorTextOn": "auto", + "label": "F", + "vertical": false, + "wrap": false, + "on": 1, + "off": 0, + "mode": "push", + "doubleTap": false, + "decoupled": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "if(value === 1){\n getVar(getProp(\"parent\", \"id\") + '_canvas', 'reset')()\n}" + }, + { + "type": "range", + "top": 0, + "left": 50, + "lock": false, + "id": "@{parent.id}_rslider", + "visible": true, + "interaction": true, + "comments": "", + "width": "auto", + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": ":host {\n\n width: calc(100% - 100rem);\n\n}", + "design": "default", + "knobSize": "auto", + "horizontal": true, + "pips": false, + "dashed": false, + "gradient": [], + "snap": true, + "spring": false, + "doubleTap": false, + "range": { + "min": 0, + "max": 5 + }, + "logScale": false, + "sensitivity": 1, + "steps": "", + "value": "[@{@{parent.id}_input_min.value}, @{@{parent.id}_input_max.value}]", + "default": [ + 0.5, + 2 + ], + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "getVar(getProp(\"parent\", \"id\") + '_canvas', 'update')()", + "onTouch": "" + }, + { + "type": "input", + "top": 0, + "left": "auto", + "lock": false, + "id": "@{parent.id}_input_max", + "visible": true, + "interaction": true, + "comments": "", + "width": 50, + "height": "auto", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": ":host {\n\n left: calc(100% - 50rem);\n\n}", + "align": "center", + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "value": "@{@{parent.id}_rslider.value.1}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "" + }, + { + "type": "input", + "top": 0, + "left": 0, + "lock": false, + "id": "@{parent.id}_input_min", + "visible": true, + "comments": "", + "width": 50, + "height": "auto", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "@{@{parent.id}_rslider.value.0}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "typeTags": "", + "ignoreDefaults": false, + "bypass": true + }, + { + "type": "text", + "top": "auto", + "left": "auto", + "lock": false, + "id": "@{parent.id}_mpos", + "visible": true, + "comments": "", + "width": 130, + "height": 40, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": ":host {\n\n top: calc(100% - 40rem);\n left: calc(50% - 65rem);\n\n}", + "align": "center", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "vertical": false, + "wrap": false + } + ], + "tabs": [] + } +} \ No newline at end of file diff --git a/open_stage_control/fragments/range_slider.json b/open_stage_control/fragments/range_slider.json new file mode 100644 index 0000000..2b39825 --- /dev/null +++ b/open_stage_control/fragments/range_slider.json @@ -0,0 +1,228 @@ +{ + "version": "1.22.0", + "createdWith": "Open Stage Control", + "type": "fragment", + "content": { + "type": "panel", + "top": 0, + "left": 0, + "lock": false, + "id": "@{parent.id}_val", + "visible": true, + "interaction": true, + "comments": "", + "width": 130, + "height": 340, + "expand": true, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "variables": "@{parent.variables}", + "traversing": false, + "value": "@{this.id}_rslider", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "input", + "top": "auto", + "left": 0, + "lock": false, + "id": "@{parent.id}_input_min", + "visible": true, + "interaction": true, + "comments": "", + "width": "100%", + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": ":host {\n\n top: calc(100% - 30rem);\n\n}", + "align": "center", + "unit": "", + "asYouType": false, + "numeric": true, + "validation": "", + "maxLength": "", + "value": "@{@{parent.id}_rslider.value.0}", + "default": "@{parent.variables.min}", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": "@{parent.variables.decimals}", + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "" + }, + { + "type": "range", + "top": 60, + "left": 0, + "lock": false, + "id": "@{parent.id}_rslider", + "visible": true, + "interaction": true, + "comments": "", + "width": "100%", + "height": "auto", + "expand": false, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": ":host {\n\n height: calc(100% - 90rem);\n\n}", + "design": "default", + "knobSize": "auto", + "horizontal": false, + "pips": false, + "dashed": false, + "gradient": [], + "snap": true, + "spring": false, + "doubleTap": false, + "range": "{\n \"min\": @{parent.variables.min},\n \"max\": @{parent.variables.max}\n}", + "logScale": false, + "sensitivity": 1, + "steps": "", + "value": "[@{@{parent.id}_input_min.value}, @{@{parent.id}_input_max.value}]", + "default": "[\n @{parent.variables.min},\n @{parent.variables.max}\n]", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "i", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "var parentVariables = getProp('parent', 'variables')\nif (parentVariables.grandparent) {\n set(parentVariables.grandparent + '_vals', value)\n}", + "onTouch": "" + }, + { + "type": "input", + "width": "100%", + "height": 30, + "left": 0, + "top": 30, + "lock": false, + "id": "@{parent.id}_input_max", + "visible": true, + "interaction": true, + "comments": "", + "expand": "false", + "css": "", + "address": "auto", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "align": "center", + "unit": "", + "asYouType": false, + "numeric": true, + "validation": "", + "maxLength": "", + "value": "@{@{parent.id}_rslider.value.1}", + "default": "@{parent.variables.max}", + "linkId": "", + "preArgs": "", + "typeTags": "", + "decimals": "@{parent.variables.decimals}", + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "" + }, + { + "type": "text", + "top": 0, + "left": 0, + "lock": false, + "id": "@{parent.id}_rslider_label", + "visible": true, + "comments": "", + "width": "100%", + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "align": "center", + "value": "@{parent.variables.rslider_label}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "" + } + ], + "tabs": [] + } +} \ No newline at end of file diff --git a/open_stage_control/fragments/slider.json b/open_stage_control/fragments/slider.json new file mode 100644 index 0000000..6284252 --- /dev/null +++ b/open_stage_control/fragments/slider.json @@ -0,0 +1,186 @@ +{ + "version": "1.22.0", + "createdWith": "Open Stage Control", + "type": "fragment", + "content": { + "type": "panel", + "top": 0, + "left": 0, + "lock": false, + "id": "@{parent.id}_val", + "visible": true, + "interaction": true, + "comments": "", + "width": "100%", + "height": "100%", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": ":host {\n\n left: calc(100% - 80rem);\n\n}", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "fader", + "top": 30, + "left": 0, + "lock": false, + "id": "@{parent.id}_slider", + "visible": true, + "comments": "", + "width": "100%", + "height": "auto", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": ":host {\n\n height: calc(100% - 60rem);\n\n}", + "value": "@{@{parent.id}_input.value}", + "default": 0.75, + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "var parentVariables = getProp('parent', 'variables')\nif (parentVariables.grandparent) {\n set(parentVariables.grandparent + '_vals', value)\n}", + "interaction": true, + "typeTags": "", + "ignoreDefaults": false, + "bypass": false, + "design": "default", + "knobSize": "auto", + "horizontal": false, + "pips": false, + "dashed": false, + "gradient": [], + "snap": true, + "spring": false, + "doubleTap": false, + "range": "{\n \"min\": @{parent.variables.min},\n \"max\": @{parent.variables.max}\n}", + "logScale": false, + "sensitivity": 1, + "steps": "", + "onTouch": "", + "origin": "auto" + }, + { + "type": "input", + "top": "auto", + "left": 0, + "lock": false, + "id": "@{parent.id}_input", + "visible": true, + "comments": "", + "width": "100%", + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": ":host {\n\n top: calc(100% - 30rem);\n\n}", + "align": "center", + "value": "@{@{parent.id}_slider.value}", + "default": 0.75, + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "typeTags": "", + "ignoreDefaults": false, + "bypass": true + }, + { + "type": "text", + "top": 0, + "left": 0, + "lock": false, + "id": "@{parent.id}_slider_label", + "visible": true, + "comments": "", + "width": "100%", + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "align": "center", + "value": "@{parent.variables.slider_label}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "" + } + ], + "tabs": [] + } +} \ No newline at end of file diff --git a/open_stage_control/modules/custom_module.js b/open_stage_control/modules/custom_module.js new file mode 100644 index 0000000..0186829 --- /dev/null +++ b/open_stage_control/modules/custom_module.js @@ -0,0 +1,277 @@ +const {resolve} = nativeRequire("path"); +var fs = nativeRequire("fs"); + +stringifyToDepth = function(data, maxDepth){ + var prettyString = "" + var rCount = 0 + var writeArray + var indent; + + if(maxDepth === 0) { + JSON.stringify(data) + } else { + indent = function(size) {return Array.from({length: size}, () => " ").join("")} + writeArray = function(array) { + prettyString = prettyString + indent(rCount) + "[\n" + rCount = rCount + 1 + if(rCount < maxDepth) { + array.forEach(item => writeArray(item)) + } else { + var formmattedArray; + formattedArray = array.map(item => indent(rCount) + JSON.stringify(item)).join(",\n") + formattedArray = formattedArray.replaceAll("[", "[ ").replaceAll("]", " ]").replaceAll(",", ", ") + prettyString = prettyString + formattedArray + } + rCount = rCount - 1; + prettyString = prettyString + "\n" + indent(rCount) + "],\n"; + } + + writeArray(data) + prettyString = prettyString.replaceAll(",\n\n", "\n").slice(0, -2); + return prettyString + } +} + +module.exports = { + + init: function(){ + // this will be executed once when the osc server starts + }, + + oscInFilter:function(data) { + + var {host, port, address, args} = data + + //console.log(data) + + if (address === '/playing') { + + var modelPath = resolve(args[0].value) + var model = loadJSON(modelPath) + //receive('/STATE/OPEN', guiStatePath) + + receive("/ref_uid", model.ref_uid) + + receive("/order_seed", model.order_seed) + receive("/dur_seed", model.dur_seed) + receive("/weights_seed", model.motifs_seed) + + + var envValsFlat = model.entrances_probs_vals.slice(5) + var envSize = envValsFlat.length / 2 + var envVals = new Array(64).fill({type: 'f', value: 0}) + for (var i = 0; i < envSize; i++) { + envVals[i] = [envValsFlat[i * 2], envValsFlat[i * 2 + 1]] + } + receive("/entrances_probs_dur_env_size", envSize) + receive("/entrances_probs_chord_val_slider", model.entrances_probs_vals[0]) + receive("/entrances_probs_pad_val_rslider", model.entrances_probs_vals.slice(1, 3)) + receive("/entrances_probs_dur_env_rslider", ...model.entrances_probs_vals.slice(3, 5)) + receive("/entrances_probs_dur_env_canvas", ...envVals) + + var envValsFlat = model.passages_probs_vals.slice(5) + var envSize = envValsFlat.length / 2 + var envVals = new Array(64).fill({type: 'f', value: 0}) + for (var i = 0; i < envSize; i++) { + envVals[i] = [envValsFlat[i * 2], envValsFlat[i * 2 + 1]] + } + receive("/passages_probs_dur_env_size", envSize) + receive("/passages_probs_chord_val_slider", model.passages_probs_vals[0]) + receive("/passages_probs_pad_val_rslider", model.passages_probs_vals.slice(1, 3)) + receive("/passages_probs_dur_env_rslider", ...model.passages_probs_vals.slice(3, 5)) + receive("/passages_probs_dur_env_canvas", ...envVals) + + var envValsFlat = model.exits_probs_vals.slice(5) + var envSize = envValsFlat.length / 2 + var envVals = new Array(64).fill({type: 'f', value: 0}) + for (var i = 0; i < envSize; i++) { + envVals[i] = [envValsFlat[i * 2], envValsFlat[i * 2 + 1]] + } + receive("/exits_probs_dur_env_size", envSize) + receive("/exits_probs_chord_val_slider", model.exits_probs_vals[0]) + receive("/exits_probs_pad_val_rslider", model.exits_probs_vals.slice(1, 3)) + receive("/exits_probs_dur_env_rslider", ...model.exits_probs_vals.slice(3, 5)) + receive("/exits_probs_dur_env_canvas", ...envVals) + + // no idea why I need to call the range sliders twice + receive("/range_matrix/0_val_rslider", ...model.ranges[0]) + receive("/range_matrix/1_val_rslider", ...model.ranges[1]) + receive("/range_matrix/2_val_rslider", ...model.ranges[2]) + receive("/range_matrix/3_val_rslider", ...model.ranges[3]) + + receive("/passages_weights/0_val_slider", model.passages_weights[0]) + receive("/passages_weights/1_val_slider", model.passages_weights[1]) + receive("/passages_weights/2_val_slider", model.passages_weights[2]) + receive("/passages_weights/3_val_slider", model.passages_weights[3]) + receive("/passages_weights/4_val_slider", model.passages_weights[4]) + + receive("/order", stringifyToDepth(model.order, 1)) + + receive("/sus_weights/0_val_slider", model.sus_weights[0]) + receive("/sus_weights/1_val_slider", model.sus_weights[1]) + receive("/sus_weights/2_val_slider", model.sus_weights[2]) + + receive("/order_size_rslider", ...model.order_size) + receive("/passages_size_rslider", ...model.passages_size) + + receive("/mus_seq", stringifyToDepth(model.music_data, 3)) + receive("/cur_play_index", args[1].value) + } + + if (address === '/generated') { + + //var guiStatePath = resolve(__dirname + "/../../resources/tmp/tmp_gui_state.json") + //var musPath = resolve(__dirname + "/../../resources/tmp/tmp_music.json") + var ledgerPath = resolve(__dirname + "/../../resources/piece_ledger.json") + //var guiState = loadJSON(guiStatePath) + //var musState = loadJSON(musPath) + //guiState.mus_seq = musState.music_data + //saveJSON(guiStatePath, guiState) + var ledger = loadJSON(ledgerPath).ledger + ledger.push("tmp") + var model = JSON.parse(args[1].value); + receive("/ledger", JSON.stringify(ledger, null, ' ').replace(/['"]+/g, '')) + receive("/mus_seq", stringifyToDepth(model.music_data, 3)) + receive("/order", stringifyToDepth(model.order, 1)) + } + + if (address === '/committed') { + try { + /* + var guiStatePath = resolve(__dirname + "/../../resources/tmp/tmp_gui_state.json") + var curUID = args[0].value + var state = loadJSON(guiStatePath) + state.cur_uid = curUID + var dir = resolve(__dirname + "/../../resources/" + curUID) + if (!fs.existsSync(dir)){ + fs.mkdirSync(dir); + } + guiStatePath = resolve(__dirname + "/../../resources/" + curUID + "/" + curUID + "_gui_state.json") + saveJSON(guiStatePath, state) + */ + } catch (e) { + console.log(`error while committing`) + console.error(e) + } + + var ledgerPath = args[1].value + receive("/ledger", JSON.stringify(loadJSON(ledgerPath).ledger, null, ' ').replace(/['"]+/g, '')) + return + } + + if (address === '/load_state') { + /* + var ref_uid = args[0].value + loadState(loadJSON("../../resources/" + ref_uid + "/" + ref_uid + "_gui_state.json")) + receive('/commit') + */ + return + } + + return data + + }, + + oscOutFilter:function(data) { + + var {host, port, address, args} = data + + //console.log(data) + + if (address === '/generate') { + try { + var state = JSON.parse(args[0].value) + + //console.log(__dirname) + var modelPath = resolve(__dirname + "/../../resources/tmp/tmp_mus_model.json") + var model = {} + model.schema_version = "1.0" + model.cur_uid = "tmp" + model.ref_uid = state.ref_uid + if(model.ref_uid == "nil" || model.ref_uid == "" || model.ref_uid == "[" || model.ref_uid == "[]") {delete model["ref_uid"]} + model.order_seed = state.order_seed + model.dur_seed = state.dur_seed + model.motifs_seed = state.weights_seed + model.entrances_probs_vals = state.entrances_probs_vals + model.passages_probs_vals = state.passages_probs_vals + model.exits_probs_vals = state.exits_probs_vals + model.ranges = [ + state["range_matrix/0_val_rslider"], + state["range_matrix/1_val_rslider"], + state["range_matrix/2_val_rslider"], + state["range_matrix/3_val_rslider"] + ] + model.passages_weights = [ + state["passages_weights/0_val_slider"], + state["passages_weights/1_val_slider"], + state["passages_weights/2_val_slider"], + state["passages_weights/3_val_slider"], + state["passages_weights/4_val_slider"] + ] + if(state.order_lock == 1){ + model.order = JSON.parse(state.order) + } + model.sus_weights = [ + state["sus_weights/0_val_slider"], + state["sus_weights/1_val_slider"], + state["sus_weights/2_val_slider"] + ] + model.order_size = state.order_size_rslider + model.passages_size = state.passages_size_rslider + + model.motif_edited = false + model.order_edited = false + //console.log(model) + saveJSON(modelPath, model) + + /* + var ledgerPanelState = JSON.parse(args[1].value) + delete ledgerPanelState.ref_uid + var omitKeys = Object.keys(ledgerPanelState).concat(["generate", "commit"]) + //console.log(omitKeys[0]) + for(k in omitKeys) { + //console.log(omitKeys[k]) + delete state[omitKeys[k]] + } + var guiStatePath = resolve(__dirname + "/../../resources/tmp/tmp_gui_state.json.json") + saveJSON(guiStatePath, state) + */ + + args = args.slice(0, 1) + args[0].value = modelPath + return {host, port, address, args} + } catch (e) { + //console.log(`error while building model ${args[0].value}`) + console.log(`error while building model`) + console.error(e) + } + return + } + + if (address === '/load_ledger') { + //console.log(loadJSON(args[0].value)) + receive('/ledger', JSON.stringify(loadJSON(args[0].value).ledger, null, ' ').replace(/['"]+/g, '')) + return data + } + + if (address === '/commit') { + var model = {} + model.music = JSON.parse(args[0].value) + args[0].value = JSON.stringify(model) + return {host, port, address, args} + } + + if ([/*'/commit', */'/save_ledger', '/transport'].includes(address)) { + //console.log(data) + return data + } + + return + + }, + + unload: function(){ + // this will be executed when the custom module is reloaded + }, + +} diff --git a/open_stage_control/seeds_and_ledgers_gui.json b/open_stage_control/seeds_and_ledgers_gui.json new file mode 100644 index 0000000..3669ce8 --- /dev/null +++ b/open_stage_control/seeds_and_ledgers_gui.json @@ -0,0 +1,2529 @@ +{ + "createdWith": "Open Stage Control", + "version": "1.24.0", + "type": "session", + "content": { + "type": "root", + "lock": false, + "id": "root", + "visible": true, + "interaction": true, + "comments": "", + "width": "auto", + "height": "auto", + "colorText": "auto", + "colorWidget": "auto", + "alphaFillOn": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "hideMenu": false, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "panel", + "top": 10, + "left": 770, + "lock": false, + "id": "motif_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": 560, + "height": 640, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "textarea", + "top": 50, + "left": 10, + "lock": false, + "id": "mus_seq", + "visible": true, + "comments": "", + "width": 530, + "height": 570, + "expand": false, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": 0, + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "textarea {\n white-space: pre;\n line-height: 20rem;\n font-size: 12rem;\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "//set(\"this\", JSON.stringify(JSON.parse(value), null, 5))", + "interaction": true, + "typeTags": "s", + "ignoreDefaults": false, + "bypass": false + }, + { + "type": "text", + "top": 10, + "left": 10, + "lock": false, + "id": "motif_label", + "visible": true, + "comments": "", + "width": 90, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "motif", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "vertical": false, + "wrap": false + }, + { + "type": "button", + "top": 10, + "left": 110, + "lock": false, + "id": "commit", + "visible": true, + "interaction": true, + "comments": "", + "width": 90, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "", + "default": 0, + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "if(value === 0){\n send('/commit', get(\"mus_seq\"))\n}\n ", + "colorTextOn": "auto", + "label": "auto", + "vertical": false, + "wrap": false, + "on": 1, + "off": 0, + "mode": "push", + "doubleTap": false, + "decoupled": false + } + ], + "tabs": [], + "tabsPosition": "top" + }, + { + "type": "panel", + "top": 10, + "left": 580, + "lock": false, + "id": "ledger_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": 190, + "height": 640, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": false, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "text", + "top": 10, + "left": 10, + "lock": false, + "id": "ledger_label", + "visible": true, + "comments": "", + "width": 70, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "ledger", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "vertical": false, + "wrap": false, + "align": "center" + }, + { + "type": "file", + "top": 50, + "left": 10, + "lock": false, + "id": "load_ledger", + "visible": true, + "interaction": true, + "comments": "", + "width": 70, + "height": 30.000000000000004, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "open", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "set(\"this\", \"open\", {send:false})", + "align": "center", + "hidePath": true, + "mode": "open", + "directory": "Sketches/seeds_and_ledgers/resources", + "extension": "*", + "allowDir": false + }, + { + "type": "panel", + "top": 130, + "left": 10, + "lock": false, + "id": "sequencer_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": 180, + "height": 600, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": 0, + "borderRadius": 0, + "padding": 0, + "html": "", + "css": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": false, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "widgets": [ + { + "type": "panel", + "top": 21, + "left": 0, + "lock": false, + "id": "ledger_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": 170, + "height": 460, + "expand": true, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": 0, + "borderRadius": 0, + "padding": 0, + "html": "", + "css": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": "auto", + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "widgets": [ + { + "type": "variable", + "lock": false, + "id": "ledger_switch_vals", + "comments": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "variable", + "lock": false, + "id": "ledger_switch_indices", + "comments": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "variable", + "lock": false, + "id": "ledger_size", + "comments": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "/*\nvar array = Array(value + 2).fill().map((element, index) => index)\nconsole.log(array)\nset('ledger_switch_vals', array)\n*/" + }, + { + "type": "textarea", + "top": 0, + "left": 40, + "lock": false, + "id": "ledger", + "visible": true, + "interaction": true, + "comments": "", + "width": 90, + "height": "VAR{\"height\", 100}", + "expand": true, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "textarea {\n overflow-y: hidden;\n line-height: VAR{\"line-height\", 20}rem;\n font-size: VAR{\"font-size\", 12}rem;\n padding-left: 10rem\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "setVar(\"this\", \"height\", 0)\nvar lines = get(\"this\").split(/\\r|\\r\\n|\\n/);\nsetVar(\"this\", \"height\", (lines.length * getVar(\"this\", \"line-height\") + 6));\n\nsetVar(\"cur_play_index\", \"height\", getVar(\"this\", \"height\"))\nsetVar(\"cur_play_index_switch\", \"height\", getVar(\"this\", \"height\"))\n\nsetVar(\"start_play_index\", \"height\", getVar(\"this\", \"height\"))\nsetVar(\"start_play_index_switch\", \"height\", getVar(\"this\", \"height\"))\n\nsetVar(\"ledger_panel\", \"height\", getVar(\"this\", \"height\"))\n\nsetVar(\"ref_uid\", \"height\", getVar(\"this\", \"height\"))\nsetVar(\"ref_uid_switch\", \"height\", getVar(\"this\", \"height\"))\n\nvar switchVals = lines.map((element, index) => element.trim().replace(',',''))\nvar switchIndices = lines.map((element, index) => index - 1)\nset(\"ledger_switch_vals\", switchVals)\nset(\"ledger_switch_indices\", switchIndices)" + }, + { + "type": "switch", + "top": 0, + "left": 0, + "lock": false, + "id": "ref_uid", + "visible": true, + "interaction": true, + "comments": "", + "width": 20, + "height": "VAR{\"height\", 100}", + "expand": "false", + "colorText": "rgba(216,222,233,1)", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": 2, + "html": "", + "css": ":host {\n font-size: 0\n}", + "colorTextOn": "auto", + "layout": "vertical", + "gridTemplate": "", + "wrap": false, + "values": "@{ledger_switch_vals}", + "mode": "tap", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "switch", + "top": 0, + "left": 0, + "lock": false, + "id": "ref_uid_switch", + "visible": true, + "interaction": true, + "comments": "", + "width": 20, + "height": "VAR{\"height\", 100}", + "expand": "false", + "colorText": "rgba(216,222,233,1)", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": 2, + "html": "", + "css": ":host {\n font-size: 0\n}", + "colorTextOn": "auto", + "layout": "vertical", + "gridTemplate": "", + "wrap": false, + "values": "@{ledger_switch_vals}", + "mode": "tap", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "if(value === get(\"ref_uid\")){\n set(\"ref_uid\", \"\")\n} else {\n set(\"ref_uid\", value)\n}\nset(\"this\", \"\")" + }, + { + "type": "switch", + "top": 0, + "left": 20, + "lock": false, + "id": "start_play_index", + "visible": true, + "interaction": true, + "comments": "", + "width": 20, + "height": "VAR{\"height\", 100}", + "expand": "false", + "colorText": "rgba(216,222,233,1)", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": 2, + "html": "", + "css": ":host {\n font-size: 0\n}", + "colorTextOn": "auto", + "layout": "vertical", + "gridTemplate": "", + "wrap": false, + "values": "@{ledger_switch_indices}", + "mode": "click", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "switch", + "top": 0, + "left": 20, + "lock": false, + "id": "start_play_index_switch", + "visible": true, + "interaction": true, + "comments": "", + "width": 20, + "height": "VAR{\"height\", 100}", + "expand": "false", + "colorText": "rgba(216,222,233,1)", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": 2, + "html": "", + "css": ":host {\n font-size: 0\n}", + "colorTextOn": "auto", + "layout": "vertical", + "gridTemplate": "", + "wrap": false, + "values": "@{ledger_switch_indices}", + "mode": "click", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "if(value === get(\"start_play_index\")){\n set(\"start_play_index\", \"\")\n} else {\n set(\"start_play_index\", value)\n}\nset(\"this\", \"\")" + }, + { + "type": "switch", + "top": 0, + "left": 130, + "lock": false, + "id": "cur_play_index", + "visible": true, + "comments": "", + "width": 20, + "height": "VAR{\"height\", 100}", + "expand": "false", + "colorText": "rgba(216,222,233,1)", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": 2, + "html": "", + "css": ":host {\n font-size: 0\n}", + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorTextOn": "auto", + "mode": "click", + "typeTags": "", + "ignoreDefaults": false, + "bypass": false, + "layout": "vertical", + "gridTemplate": "", + "values": "@{ledger_switch_indices}" + }, + { + "type": "switch", + "top": 0, + "left": 130, + "lock": false, + "id": "cur_play_index_switch", + "visible": true, + "comments": "", + "width": 20, + "height": "VAR{\"height\", 100}", + "expand": "false", + "colorText": "rgba(216,222,233,1)", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": 2, + "html": "", + "css": ":host {\n font-size: 0\n}", + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "locals.last = \"\"", + "onValue": "if(value === get(\"cur_play_index\")){\n set(\"cur_play_index\", \"\")\n} else {\n set(\"cur_play_index\", value)\n}\nset(\"this\", \"\")", + "interaction": true, + "colorTextOn": "auto", + "mode": "tap", + "typeTags": "", + "ignoreDefaults": false, + "bypass": false, + "layout": "vertical", + "gridTemplate": "", + "values": "@{ledger_switch_indices}" + } + ], + "tabs": [], + "tabsPosition": "top" + }, + { + "type": "button", + "top": 0, + "left": 0, + "lock": false, + "id": "ref_uid_lock", + "visible": true, + "comments": "", + "width": 20, + "height": 20.727272727272727, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorTextOn": "auto", + "label": "L", + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": true + }, + { + "type": "variable", + "lock": false, + "id": "current_uid", + "comments": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "", + "typeTags": "s", + "ignoreDefaults": false, + "bypass": true + } + ], + "tabs": [], + "tabsPosition": "top" + }, + { + "type": "file", + "top": 50, + "left": 90, + "lock": false, + "id": "save_ledger", + "visible": true, + "interaction": true, + "comments": "", + "width": 70, + "height": 30.000000000000004, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "save", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "set(\"this\", \"save\", {send:false})", + "align": "center", + "hidePath": true, + "mode": "open", + "directory": "Sketches/seeds_and_ledgers/resources", + "extension": "*", + "allowDir": false + }, + { + "type": "button", + "top": 90, + "left": 10, + "lock": false, + "id": "transport", + "visible": true, + "interaction": true, + "comments": "", + "width": 150, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorTextOn": "auto", + "label": "#{@{this} == 0 ? \"play\" : \"stop\"}", + "vertical": false, + "wrap": false, + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 0, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "if(value === 1){\n send(false, \"/transport\", 1, get(\"start_play_index\"));\n} else {\n send(false, \"/transport\", 0, get(\"start_play_index\"));\n}" + } + ], + "tabs": [], + "tabsPosition": "top" + }, + { + "type": "panel", + "top": 10, + "left": 30, + "lock": false, + "id": "seeds_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": 550, + "height": 640, + "expand": false, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "text", + "top": 10, + "left": 10, + "lock": false, + "id": "seeds_label", + "visible": true, + "comments": "", + "width": 80, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "seeds", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "vertical": false, + "wrap": false, + "align": "center" + }, + { + "type": "panel", + "top": 90, + "left": 10, + "lock": false, + "id": "seeds_tab_panel", + "visible": true, + "comments": "", + "width": "96.3%", + "height": "84.13%", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": 0, + "html": "", + "css": "> inner > .navigation {\n height: 35rem;\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": true, + "widgets": [], + "tabs": [ + { + "type": "tab", + "lock": false, + "id": "instrumentation", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "label": "auto", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "textarea", + "top": 270, + "left": 290, + "lock": false, + "id": "order", + "visible": true, + "interaction": true, + "comments": "", + "width": "41.18%", + "height": "41.24%", + "expand": false, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "textarea {\n white-space: pre;\n line-height: 1.5;\n font-size: 12px;\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "s", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "button", + "top": 270, + "left": 480, + "lock": false, + "id": "order_lock", + "visible": true, + "comments": "", + "width": 20, + "height": 20, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorTextOn": "auto", + "label": "L", + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": false + }, + { + "type": "panel", + "top": 190, + "left": 290, + "lock": false, + "id": "order_size", + "visible": true, + "comments": "", + "width": 210, + "height": 40, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": false, + "widgets": [ + { + "type": "range", + "top": 0, + "left": 40, + "lock": false, + "id": "@{parent.id}_rslider", + "visible": true, + "interaction": true, + "comments": "", + "width": 120, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "design": "default", + "knobSize": "auto", + "horizontal": true, + "pips": false, + "dashed": false, + "gradient": [], + "snap": true, + "spring": false, + "doubleTap": false, + "range": { + "min": 1, + "max": 10 + }, + "logScale": false, + "sensitivity": 1, + "steps": 10, + "value": "[@{@{parent.id}_input_min.value}, @{@{parent.id}_input_max.value}]", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "i", + "decimals": 0, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "onTouch": "" + }, + { + "type": "input", + "top": 0, + "left": 160, + "lock": false, + "id": "@{parent.id}_input_max", + "visible": true, + "comments": "", + "width": 40, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "@{@{parent.id}_rslider.value.1}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "typeTags": "i", + "ignoreDefaults": false, + "bypass": false + }, + { + "type": "input", + "top": 0, + "left": 0, + "lock": false, + "id": "@{parent.id}_input_min", + "visible": true, + "comments": "", + "width": 40, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "@{@{parent.id}_rslider.value.0}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "typeTags": "i", + "ignoreDefaults": false, + "bypass": false + } + ], + "tabs": [], + "tabsPosition": "top" + }, + { + "type": "panel", + "top": 230, + "left": 290, + "lock": false, + "id": "passages_size", + "visible": true, + "interaction": true, + "comments": "", + "width": 210, + "height": 40, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "range", + "top": 0, + "left": 40, + "lock": false, + "id": "@{parent.id}_rslider", + "visible": true, + "interaction": true, + "comments": "", + "width": 120, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "design": "default", + "knobSize": "auto", + "horizontal": true, + "pips": false, + "dashed": false, + "gradient": [], + "snap": true, + "spring": false, + "doubleTap": false, + "range": { + "min": 0, + "max": 10 + }, + "logScale": false, + "sensitivity": 1, + "steps": 11, + "value": "[@{@{parent.id}_input_min.value}, @{@{parent.id}_input_max.value}]", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "i", + "decimals": 0, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "onTouch": "" + }, + { + "type": "input", + "top": 0, + "left": 160, + "lock": false, + "id": "@{parent.id}_input_max", + "visible": true, + "comments": "", + "width": 40, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "@{@{parent.id}_rslider.value.1}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "typeTags": "", + "ignoreDefaults": false, + "bypass": false + }, + { + "type": "input", + "top": 0, + "left": 0, + "lock": false, + "id": "@{parent.id}_input_min", + "visible": true, + "comments": "", + "width": 40, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "@{@{parent.id}_rslider.value.0}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "set(\"passages_size\", [value, get(\"passages_size_v2\")])", + "interaction": true, + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "typeTags": "", + "ignoreDefaults": false, + "bypass": false + } + ], + "tabs": [], + "tabsPosition": "top" + }, + { + "type": "matrix", + "top": 10, + "left": 290, + "lock": false, + "id": "sus_weights", + "visible": true, + "interaction": true, + "comments": "", + "width": "41.18%", + "height": "37.11%", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "horizontal", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "widgetType": "fragment", + "quantity": 3, + "props": "{\n \"file\": \"fragments/slider.json\",\n \"props\": {\n \"variables\": #{{\n \"n\": $, \"slider_label\": [\"1\", \"2\", \"3\"][$], \n \"min\": 0.0, \"max\": 1.0\n }}\n }\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [], + "tabs": [], + "tabsPosition": "top" + }, + { + "type": "matrix", + "top": 10, + "left": 10, + "lock": false, + "id": "range_matrix", + "visible": true, + "interaction": true, + "comments": "", + "width": "52%", + "height": "95.24%", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "horizontal", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "widgetType": "fragment", + "quantity": 4, + "props": "{\n \"file\": \"fragments/range_slider.json\",\n \"props\": {\n \"variables\": #{{\n \"n\": $, \"min\": -1200, \"max\": 2400, \n \"rslider_label\": [\"IV\", \"III\", \"II\", \"I\"][$], \n \"decimals\": 0\n }\n }}\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [], + "tabs": [], + "tabsPosition": "top" + } + ], + "tabs": [], + "tabsPosition": "top" + }, + { + "type": "tab", + "lock": false, + "id": "durations", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": false, + "label": "auto", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "panel", + "top": 0, + "left": 0, + "lock": false, + "id": "dur_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": "100%", + "height": "100%", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "> inner > .navigation {\n height: 30rem;\n}", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [], + "tabs": [ + { + "type": "tab", + "lock": false, + "id": "entrances", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "label": "auto", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "fragment", + "top": 50, + "left": 10, + "lock": false, + "id": "entrances", + "visible": true, + "interaction": true, + "comments": "", + "width": "96.46%", + "height": "86.09%", + "expand": "false", + "css": "", + "file": "fragments/dur_probs_panel.json", + "fallback": "", + "props": {}, + "address": "auto", + "variables": "@{parent.variables}" + }, + { + "type": "switch", + "top": 10, + "left": 10, + "lock": false, + "id": "entrances_probs_sync", + "visible": true, + "interaction": true, + "comments": "", + "width": 490, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorTextOn": "auto", + "layout": "horizontal", + "gridTemplate": "", + "wrap": false, + "values": { + "sync to entrances": "entrances", + "sync to passages": "passages", + "sync to exits": "exits" + }, + "mode": "tap", + "value": "", + "default": "entrances", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "set(\"@{parent.id}_probs_vals\", get(value + \"_probs_vals\"))" + } + ], + "tabs": [], + "tabsPosition": "top" + }, + { + "type": "tab", + "lock": false, + "id": "passages", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "label": "auto", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "fragment", + "top": 50, + "left": 10, + "lock": false, + "id": "passages", + "visible": true, + "interaction": true, + "comments": "", + "width": "96.46%", + "height": "86.09%", + "expand": "false", + "css": "", + "file": "fragments/dur_probs_panel.json", + "fallback": "", + "props": {}, + "address": "auto", + "variables": "@{parent.variables}" + }, + { + "type": "switch", + "top": 10, + "left": 10, + "lock": false, + "id": "passages_probs_sync", + "visible": true, + "interaction": true, + "comments": "", + "width": 490, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorTextOn": "auto", + "layout": "horizontal", + "gridTemplate": "", + "wrap": false, + "values": { + "sync to entrances": "entrances", + "sync to passages": "passages", + "sync to exits": "exits" + }, + "mode": "tap", + "value": "", + "default": "passages", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "set(\"@{parent.id}_probs_vals\", get(value + \"_probs_vals\"))" + } + ], + "tabs": [], + "tabsPosition": "top" + }, + { + "type": "tab", + "lock": false, + "id": "exits", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "label": "auto", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "fragment", + "top": 50, + "left": 10, + "lock": false, + "id": "exits", + "visible": true, + "interaction": true, + "comments": "", + "width": "96.46%", + "height": "86.09%", + "expand": "false", + "css": "", + "file": "fragments/dur_probs_panel.json", + "fallback": "", + "props": {}, + "address": "auto", + "variables": "@{parent.variables}" + }, + { + "type": "switch", + "top": 10, + "left": 10, + "lock": false, + "id": "exits_probs_sync", + "visible": true, + "interaction": true, + "comments": "", + "width": 490, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorTextOn": "auto", + "layout": "horizontal", + "gridTemplate": "", + "wrap": false, + "values": { + "sync to entrances": "entrances", + "sync to passages": "passages", + "sync to exits": "exits" + }, + "mode": "tap", + "value": "", + "default": "exits", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "set(\"@{parent.id}_probs_vals\", get(value + \"_probs_vals\"))" + } + ], + "tabs": [], + "tabsPosition": "top" + } + ], + "tabsPosition": "top" + } + ], + "tabs": [], + "tabsPosition": "top" + }, + { + "type": "tab", + "lock": false, + "id": "weights", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": false, + "label": "melody weights", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "fragment", + "top": 10, + "left": 10, + "lock": false, + "id": "step_env", + "visible": true, + "interaction": true, + "comments": "", + "width": "96.53%", + "height": 260, + "expand": "false", + "css": "", + "file": "fragments/env.json", + "fallback": "", + "props": {}, + "address": "auto", + "variables": "@{parent.variables}" + }, + { + "type": "matrix", + "top": 280, + "left": 10, + "lock": false, + "id": "passages_weights", + "visible": true, + "interaction": true, + "comments": "", + "width": "96.53%", + "height": "40.57%", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "horizontal", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "widgetType": "fragment", + "quantity": 5, + "props": "{\n \"file\": \"fragments/slider.json\",\n \"props\": {\n \"variables\": #{{\n \"n\": $, \"slider_label\": [\"step\", \"dc\", \"range\", \"registration\", \"hd\"][$], \n \"min\": 0, \"max\": 1\n }}\n }\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [], + "tabs": [], + "tabsPosition": "top" + } + ], + "tabs": [], + "tabsPosition": "top" + } + ], + "tabsPosition": "top" + }, + { + "type": "button", + "top": 50, + "left": 130, + "lock": false, + "id": "order_seed_lock", + "visible": true, + "comments": "", + "width": 30.000000000000004, + "height": 30.000000000000004, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorTextOn": "auto", + "label": "L", + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": true + }, + { + "type": "input", + "top": 50, + "left": 50, + "lock": false, + "id": "order_seed", + "visible": true, + "interaction": true, + "comments": "", + "width": 80, + "height": 30.000000000000004, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "button", + "top": 50, + "left": 300, + "lock": false, + "id": "dur_seed_lock", + "visible": true, + "comments": "", + "width": 29.999999999999996, + "height": 29.999999999999996, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorTextOn": "auto", + "label": "L", + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": true + }, + { + "type": "input", + "top": 50, + "left": 220, + "lock": false, + "id": "dur_seed", + "visible": true, + "interaction": true, + "comments": "", + "width": 80, + "height": 30.000000000000004, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "button", + "top": 50, + "left": 460, + "lock": false, + "id": "weights_seed_lock", + "visible": true, + "comments": "", + "width": 29.999999999999996, + "height": 29.999999999999996, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorTextOn": "auto", + "label": "L", + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": true + }, + { + "type": "input", + "top": 50, + "left": 380, + "lock": false, + "id": "weights_seed", + "visible": true, + "interaction": true, + "comments": "", + "width": 80, + "height": 30.000000000000004, + "expand": false, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "button", + "top": 10, + "left": 100, + "lock": false, + "id": "generate", + "visible": true, + "interaction": true, + "comments": "", + "width": 90, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorTextOn": "auto", + "label": "generate", + "vertical": false, + "wrap": false, + "on": 1, + "off": 0, + "mode": "push", + "doubleTap": false, + "decoupled": false, + "value": "", + "default": 0, + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "if(value === 0){\n var minSeed = 100000\n var maxSeed = 999999\n \n if(get(\"dur_seed_lock\") === 0){\n set(\"dur_seed\", Math.floor(Math.random() * (maxSeed - minSeed) + minSeed))\n }\n \n if(get(\"order_seed_lock\") === 0){\n set(\"order_seed\", Math.floor(Math.random() * (maxSeed - minSeed) + minSeed))\n }\n \n if(get(\"weights_seed_lock\") === 0){\n set(\"weights_seed\", Math.floor(Math.random() * (maxSeed - minSeed) + minSeed))\n }\n \n set(\"entrances_probs_vals\", \"\")\n set(\"passages_probs_vals\", \"\")\n set(\"exits_probs_vals\", \"\")\n \n send('/generate', stateGet('root'), stateGet('ledger_panel'))\n\n}" + } + ], + "tabs": [], + "tabsPosition": "top" + } + ], + "tabs": [], + "tabsPosition": "top" + } +} \ No newline at end of file diff --git a/open_stage_control/seeds_and_ledgers_gui_bak.json b/open_stage_control/seeds_and_ledgers_gui_bak.json new file mode 100644 index 0000000..bb7088a --- /dev/null +++ b/open_stage_control/seeds_and_ledgers_gui_bak.json @@ -0,0 +1,2443 @@ +{ + "createdWith": "Open Stage Control", + "version": "1.22.0", + "type": "session", + "content": { + "type": "root", + "lock": false, + "id": "root", + "visible": true, + "interaction": true, + "comments": "", + "width": "auto", + "height": "auto", + "colorText": "auto", + "colorWidget": "auto", + "alphaFillOn": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "hideMenu": false, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "panel", + "top": 10, + "left": 770, + "lock": false, + "id": "motif_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": 560, + "height": 640, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "textarea", + "top": 40, + "left": 10, + "lock": false, + "id": "mus_seq", + "visible": true, + "comments": "", + "width": 530, + "height": 580, + "expand": false, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": 0, + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "textarea {\n white-space: pre;\n line-height: 20rem;\n font-size: 12rem;\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "//set(\"this\", JSON.stringify(JSON.parse(value), null, 5))", + "interaction": true, + "typeTags": "s", + "ignoreDefaults": false, + "bypass": false + }, + { + "type": "text", + "top": 10, + "left": 10, + "lock": false, + "id": "motif_label", + "visible": true, + "comments": "", + "width": 90, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "motif", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "vertical": false, + "wrap": false + } + ], + "tabs": [] + }, + { + "type": "panel", + "top": 10, + "left": 580, + "lock": false, + "id": "ledger_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": 190, + "height": 640, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": false, + "innerPadding": true, + "verticalTabs": false, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "text", + "top": 10, + "left": 10, + "lock": false, + "id": "ledger_label", + "visible": true, + "comments": "", + "width": 70, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "ledger", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "vertical": false, + "wrap": false, + "align": "center" + }, + { + "type": "file", + "top": 10, + "left": 80, + "lock": false, + "id": "load_ledger", + "visible": true, + "interaction": true, + "comments": "", + "width": 80, + "height": 30.000000000000004, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "align": "center", + "hidePath": true, + "mode": "open", + "directory": "Sketches/seeds_and_ledgers/resources", + "extension": "*", + "allowDir": false + }, + { + "type": "panel", + "top": 50, + "left": 10, + "lock": false, + "id": "sequencer_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": 180, + "height": 600, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": 0, + "borderRadius": 0, + "padding": 0, + "html": "", + "css": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": false, + "innerPadding": true, + "verticalTabs": false, + "variables": "@{parent.variables}", + "traversing": false, + "widgets": [ + { + "type": "panel", + "top": 81, + "left": 0, + "lock": false, + "id": "ledger_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": 170, + "height": 480, + "expand": true, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": 0, + "borderRadius": 0, + "padding": 0, + "html": "", + "css": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": "auto", + "innerPadding": true, + "verticalTabs": false, + "variables": "@{parent.variables}", + "traversing": false, + "widgets": [ + { + "type": "switch", + "top": 0, + "left": 130, + "lock": false, + "id": "cur_play_uid", + "visible": true, + "comments": "", + "width": 20, + "height": "VAR{\"height\", 100}", + "expand": "false", + "colorText": "rgba(216,222,233,1)", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": 2, + "html": "", + "css": ":host {\n font-size: 0\n}", + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorTextOn": "auto", + "mode": "tap", + "typeTags": "", + "ignoreDefaults": false, + "bypass": false, + "layout": "vertical", + "gridTemplate": "", + "values": "@{ledger_switch_vals}" + }, + { + "type": "variable", + "lock": false, + "id": "ledger_switch_vals", + "comments": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "variable", + "lock": false, + "id": "ledger_switch_indices", + "comments": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "variable", + "lock": false, + "id": "ledger_size", + "comments": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "/*\nvar array = Array(value + 2).fill().map((element, index) => index)\nconsole.log(array)\nset('ledger_switch_vals', array)\n*/" + }, + { + "type": "textarea", + "top": 0, + "left": 40, + "lock": false, + "id": "ledger", + "visible": true, + "interaction": true, + "comments": "", + "width": 90, + "height": "VAR{\"height\", 100}", + "expand": true, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "textarea {\n overflow-y: hidden;\n line-height: VAR{\"line-height\", 20}rem;\n font-size: VAR{\"font-size\", 12}rem;\n padding-left: 10rem\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "setVar(\"this\", \"height\", 0)\nvar lines = get(\"this\").split(/\\r|\\r\\n|\\n/);\nsetVar(\"this\", \"height\", (lines.length * getVar(\"this\", \"line-height\") + 6));\nsetVar(\"cur_play_uid\", \"height\", getVar(\"this\", \"height\"))\nsetVar(\"start_play\", \"height\", getVar(\"this\", \"height\"))\nsetVar(\"ledger_panel\", \"height\", getVar(\"this\", \"height\"))\nsetVar(\"ref_uid\", \"height\", getVar(\"this\", \"height\"))\nvar switchVals = lines.map((element, index) => element.trim().replace(',',''))\nvar switchIndices = lines.map((element, index) => index)\nset(\"ledger_switch_vals\", switchVals)\nset(\"ledger_switch_indices\", switchIndices)" + }, + { + "type": "switch", + "top": 0, + "left": 0, + "lock": false, + "id": "ref_uid", + "visible": true, + "interaction": true, + "comments": "", + "width": 20, + "height": "VAR{\"height\", 100}", + "expand": "false", + "colorText": "rgba(216,222,233,1)", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": 2, + "html": "", + "css": ":host {\n font-size: 0\n}", + "colorTextOn": "auto", + "layout": "vertical", + "gridTemplate": "", + "wrap": false, + "values": "@{ledger_switch_vals}", + "mode": "tap", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "console.log(get(\"ledger_switch_vals\"))\nconsole.log(value)" + }, + { + "type": "switch", + "top": 0, + "left": 20, + "lock": false, + "id": "start_play", + "visible": true, + "interaction": true, + "comments": "", + "width": 20, + "height": "VAR{\"height\", 100}", + "expand": "false", + "colorText": "rgba(216,222,233,1)", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": 2, + "html": "", + "css": ":host {\n font-size: 0\n}", + "colorTextOn": "auto", + "layout": "vertical", + "gridTemplate": "", + "wrap": false, + "values": "@{ledger_switch_indices}", + "mode": "tap", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + } + ], + "tabs": [] + }, + { + "type": "button", + "top": 60, + "left": 0, + "lock": false, + "id": "ref_uid_lock", + "visible": true, + "comments": "", + "width": 20, + "height": 20.727272727272727, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorTextOn": "auto", + "label": "L", + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": true + }, + { + "type": "input", + "top": 60, + "left": 40, + "lock": false, + "id": "current_uid", + "visible": true, + "comments": "", + "width": 90, + "height": 20, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "typeTags": "s", + "ignoreDefaults": false, + "bypass": true, + "unit": "", + "asYouType": true, + "numeric": true, + "validation": "", + "maxLength": "" + }, + { + "type": "button", + "top": 60, + "left": 130, + "lock": false, + "id": "current_uid_lock", + "visible": true, + "interaction": true, + "comments": "", + "width": 20, + "height": 20, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "colorTextOn": "auto", + "label": "L", + "vertical": false, + "wrap": false, + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false + }, + { + "type": "button", + "top": 30, + "left": 0, + "lock": false, + "id": "transport", + "visible": true, + "interaction": true, + "comments": "", + "width": 150, + "height": 20, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorTextOn": "auto", + "label": "#{@{this} == 0 ? \"play\" : \"stop\"}", + "vertical": false, + "wrap": false, + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 0, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "if(value === 1){\n console.log(get(\"start_play\"))\n send(false, \"/transport\", 1, get(\"start_play\") - 1);\n} else {\n send(false, \"/transport\", 0, get(\"start_play\") - 1);\n}" + }, + { + "type": "button", + "top": 0, + "left": 0, + "lock": false, + "id": "gen", + "visible": true, + "interaction": true, + "comments": "", + "width": 70, + "height": 20, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorTextOn": "auto", + "label": "generate", + "vertical": false, + "wrap": false, + "on": 1, + "off": 0, + "mode": "push", + "doubleTap": false, + "decoupled": false, + "value": "", + "default": 0, + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "if(value === 1){\n var sVal = 1\n var order = null\n var passage = null\n var rUID = get(\"ref_uid\")\n var durSeed;\n var orderSeed;\n var weightSeed\n \n if(get(\"ref_uid\")){\n rUID = get(\"ref_uid\")\n } else {\n rUID = 1\n }\n \n if(get(\"dur_seed_lock\") == 1){\n durSeed = get(\"dur_seed\")\n } else {\n durSeed = 1\n }\n \n if(get(\"order_seed_lock\") == 1){\n orderSeed = get(\"order_seed\")\n } else {\n orderSeed = 1\n }\n \n if(get(\"weights_seed_lock\") == 1){\n weightSeed = get(\"weights_seed\")\n } else {\n weightSeed = 1\n }\n \n /*\n if(get(\"order_lock\") == 1){\n order = get(\"order\").replace(/\\s/g, \"\")\n send(false, \"/gen\", rUID, durSeed, orderSeed, weightSeed, order)\n } else {\n order = get(\"order_size\")\n passage = get(\"passage_size\")\n send(false, \"/gen\", rUID, durSeed, orderSeed, weightSeed,\n {\"type\": \"i\", \"value\": order[0]}, \n {\"type\": \"i\", \"value\": order[1]}, \n {\"type\": \"i\", \"value\": passage[0]}, \n {\"type\": \"i\", \"value\": passage[1]});\n }\n */\n \n send('custom:module', '/gen', stateGet('root'))\n\n}" + }, + { + "type": "button", + "top": 0, + "left": 80, + "lock": false, + "id": "commit", + "visible": true, + "interaction": true, + "comments": "", + "width": 70, + "height": 20, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "", + "default": 0, + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "if(value === 1){\n //send(false, \"/commit\");\n //set(\"reference_seed\", get(\"current_seed\"))\n //var lVals = get(\"ledger_switch_vals\")\n //if(get(\"ref_uid_lock\") === 0){\n // set(\"ref_uid\", lVals[lVals.length - 2])\n //}\n // set(\"current_uid\", \"\")\n send('custom:module', 'commit', get(\"current_uid\"), stateGet('root'), stateGet('ledger_panel'))\n}\n ", + "colorTextOn": "auto", + "label": "auto", + "vertical": false, + "wrap": false, + "on": 1, + "off": 0, + "mode": "push", + "doubleTap": false, + "decoupled": false + } + ], + "tabs": [] + } + ], + "tabs": [] + }, + { + "type": "panel", + "top": 10, + "left": 30, + "lock": false, + "id": "seeds_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": 550, + "height": 640, + "expand": false, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "text", + "top": 10, + "left": 10, + "lock": false, + "id": "seeds_label", + "visible": true, + "comments": "", + "width": 80, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "seeds", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "vertical": false, + "wrap": false, + "align": "center" + }, + { + "type": "panel", + "top": 90, + "left": 10, + "lock": false, + "id": "seeds_tab_panel", + "visible": true, + "comments": "", + "width": "96.3%", + "height": "84.13%", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": 0, + "html": "", + "css": "> inner > .navigation {\n height: 35rem;\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "variables": "@{parent.variables}", + "traversing": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": true, + "widgets": [], + "tabs": [ + { + "type": "tab", + "lock": false, + "id": "instrumentation", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "label": "auto", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "textarea", + "top": 270, + "left": 290, + "lock": false, + "id": "order", + "visible": true, + "interaction": true, + "comments": "", + "width": "41.18%", + "height": "41.24%", + "expand": false, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "textarea {\n white-space: pre;\n line-height: 1.5;\n font-size: 12px;\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "s", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "button", + "top": 270, + "left": 480, + "lock": false, + "id": "order_lock", + "visible": true, + "comments": "", + "width": 20, + "height": 20, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorTextOn": "auto", + "label": "L", + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": false + }, + { + "type": "panel", + "top": 190, + "left": 290, + "lock": false, + "id": "order_size_panel", + "visible": true, + "comments": "", + "width": 210, + "height": 40, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "variables": "@{parent.variables}", + "traversing": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": false, + "widgets": [ + { + "type": "range", + "top": 0, + "left": 40, + "lock": false, + "id": "order_size", + "visible": true, + "interaction": true, + "comments": "", + "width": 120, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "design": "default", + "knobSize": "auto", + "horizontal": true, + "pips": false, + "dashed": false, + "gradient": [], + "snap": true, + "spring": false, + "doubleTap": false, + "range": { + "min": 1, + "max": 10 + }, + "logScale": false, + "sensitivity": 1, + "steps": 10, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "i", + "decimals": 0, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "onTouch": "" + }, + { + "type": "input", + "top": 0, + "left": 160, + "lock": false, + "id": "order_size_v2", + "visible": true, + "comments": "", + "width": 40, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "@{order_size.value.1}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "set(\"order_size\", [get(\"order_size_v1\"), value])", + "interaction": true, + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "typeTags": "i", + "ignoreDefaults": false, + "bypass": false + }, + { + "type": "input", + "top": 0, + "left": 0, + "lock": false, + "id": "order_size_v1", + "visible": true, + "comments": "", + "width": 40, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "@{order_size.value.0}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "set(\"order_size\", [value, get(\"order_size_v2\")])", + "interaction": true, + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "typeTags": "i", + "ignoreDefaults": false, + "bypass": false + } + ], + "tabs": [] + }, + { + "type": "panel", + "top": 230, + "left": 290, + "lock": false, + "id": "passage_size_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": 210, + "height": 40, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "range", + "top": 0, + "left": 40, + "lock": false, + "id": "passage_size", + "visible": true, + "interaction": true, + "comments": "", + "width": 120, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "design": "default", + "knobSize": "auto", + "horizontal": true, + "pips": false, + "dashed": false, + "gradient": [], + "snap": true, + "spring": false, + "doubleTap": false, + "range": { + "min": 0, + "max": 10 + }, + "logScale": false, + "sensitivity": 1, + "steps": 11, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 0, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "onTouch": "" + }, + { + "type": "input", + "top": 0, + "left": 160, + "lock": false, + "id": "passage_size_v2", + "visible": true, + "comments": "", + "width": 40, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "@{passage_size.value.1}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "set(\"passage_size\", [get(\"passage_size_v1\"), value])", + "interaction": true, + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "typeTags": "", + "ignoreDefaults": false, + "bypass": false + }, + { + "type": "input", + "top": 0, + "left": 0, + "lock": false, + "id": "passage_size_v1", + "visible": true, + "comments": "", + "width": 40, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "@{passage_size.value.0}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "set(\"passage_size\", [value, get(\"passage_size_v2\")])", + "interaction": true, + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "typeTags": "", + "ignoreDefaults": false, + "bypass": false + } + ], + "tabs": [] + }, + { + "type": "matrix", + "top": 10, + "left": 290, + "lock": false, + "id": "sus_weights", + "visible": true, + "interaction": true, + "comments": "", + "width": "41.18%", + "height": "37.11%", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "horizontal", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "widgetType": "fragment", + "quantity": 3, + "props": "{\n \"file\": \"fragments/slider.json\",\n \"props\": {\n \"variables\": #{{\n \"n\": $, \"name\": [\"1\", \"2\", \"3\"][$], \n \"min\": -1200, \"max\": 2400,\n \"address\": \"/sus_weights\"\n }}\n }\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "console.log(\"test\")", + "widgets": [], + "tabs": [] + }, + { + "type": "matrix", + "top": 10, + "left": 10, + "lock": false, + "id": "range_matrix", + "visible": true, + "interaction": true, + "comments": "", + "width": "52%", + "height": "95.24%", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "horizontal", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "widgetType": "fragment", + "quantity": 4, + "props": "{\n \"file\": \"fragments/range_slider_responsive_2.json\",\n \"props\": {\n \"variables\": {\n \"n\": #{$}, \"min\": -1200, \"max\": 2400, \"address\": \"/range\"\n }\n }\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [], + "tabs": [] + } + ], + "tabs": [] + }, + { + "type": "tab", + "lock": false, + "id": "durations", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": false, + "verticalTabs": false, + "label": "auto", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "panel", + "top": 0, + "left": 0, + "lock": false, + "id": "dur_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": "100%", + "height": "100%", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "> inner > .navigation {\n height: 30rem;\n}", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [], + "tabs": [ + { + "type": "tab", + "lock": false, + "id": "entrances", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "label": "auto", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "fragment", + "top": 50, + "left": 10, + "lock": false, + "id": "entrances", + "visible": true, + "interaction": true, + "comments": "", + "width": "96.46%", + "height": "86.09%", + "expand": "false", + "css": "", + "file": "fragments/env_durs_frags.json", + "fallback": "", + "props": {}, + "address": "auto", + "variables": "@{parent.variables}" + }, + { + "type": "switch", + "top": 10, + "left": 10, + "lock": false, + "id": "entrances_probs_sync", + "visible": true, + "interaction": true, + "comments": "", + "width": 490, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorTextOn": "auto", + "layout": "horizontal", + "gridTemplate": "", + "wrap": false, + "values": { + "sync to entrances": "entrances", + "sync to passages": "passages", + "sync to exits": "exits" + }, + "mode": "tap", + "value": "", + "default": "passages", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "set(\"@{parent.id}_probs_vals\", get(value + \"_probs_vals\"))" + } + ], + "tabs": [] + }, + { + "type": "tab", + "lock": false, + "id": "passages", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "label": "auto", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "fragment", + "top": 50, + "left": 10, + "lock": false, + "id": "passages", + "visible": true, + "interaction": true, + "comments": "", + "width": "96.46%", + "height": "86.09%", + "expand": "false", + "css": "", + "file": "fragments/env_durs_frags.json", + "fallback": "", + "props": {}, + "address": "auto", + "variables": "@{parent.variables}" + }, + { + "type": "switch", + "top": 10, + "left": 10, + "lock": false, + "id": "passages_probs_sync", + "visible": true, + "interaction": true, + "comments": "", + "width": 490, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorTextOn": "auto", + "layout": "horizontal", + "gridTemplate": "", + "wrap": false, + "values": { + "sync to entrances": "entrances", + "sync to passages": "passages", + "sync to exits": "exits" + }, + "mode": "tap", + "value": "", + "default": "passages", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "set(\"@{parent.id}_probs_vals\", get(value + \"_probs_vals\"))" + } + ], + "tabs": [] + }, + { + "type": "tab", + "lock": false, + "id": "exits", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "label": "auto", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "fragment", + "top": 50, + "left": 10, + "lock": false, + "id": "exits", + "visible": true, + "interaction": true, + "comments": "", + "width": "96.46%", + "height": "86.09%", + "expand": "false", + "css": "", + "file": "fragments/env_durs_frags.json", + "fallback": "", + "props": {}, + "address": "auto", + "variables": "@{parent.variables}" + }, + { + "type": "switch", + "top": 10, + "left": 10, + "lock": false, + "id": "exits_probs_sync", + "visible": true, + "interaction": true, + "comments": "", + "width": 490, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorTextOn": "auto", + "layout": "horizontal", + "gridTemplate": "", + "wrap": false, + "values": { + "sync to entrances": "entrances", + "sync to passages": "passages", + "sync to exits": "exits" + }, + "mode": "tap", + "value": "", + "default": "passages", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "set(\"@{parent.id}_probs_vals\", get(value + \"_probs_vals\"))" + } + ], + "tabs": [] + } + ], + "verticalTabs": false + } + ], + "tabs": [] + }, + { + "type": "tab", + "lock": false, + "id": "weights", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": false, + "verticalTabs": false, + "label": "melody weights", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "fragment", + "top": 10, + "left": 10, + "lock": false, + "id": "step_env", + "visible": true, + "interaction": true, + "comments": "", + "width": "96.53%", + "height": 260, + "expand": "false", + "css": "", + "file": "fragments/env.json", + "fallback": "", + "props": {}, + "address": "auto", + "variables": "@{parent.variables}" + }, + { + "type": "matrix", + "top": 280, + "left": 10, + "lock": false, + "id": "passages_weights", + "visible": true, + "interaction": true, + "comments": "", + "width": "96.53%", + "height": "40.57%", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "horizontal", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "widgetType": "fragment", + "quantity": 5, + "props": "{\n \"file\": \"fragments/slider.json\",\n \"props\": {\n \"variables\": #{{\n \"n\": $, \"name\": [\"step\", \"dc\", \"range\", \"registration\", \"hd\"][$], \n \"min\": -1200, \"max\": 2400,\n \"address\": \"/passages_weights\"\n }}\n }\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [], + "tabs": [] + }, + { + "type": "variable", + "lock": false, + "id": "passage_weights/2_val_share", + "comments": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "console.log(value)" + } + ], + "tabs": [] + } + ] + }, + { + "type": "input", + "top": 50, + "left": 50, + "lock": false, + "id": "order_seed", + "visible": true, + "interaction": true, + "comments": "", + "width": 80, + "height": 30.000000000000004, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "button", + "top": 50, + "left": 130, + "lock": false, + "id": "dur_seed_lock", + "visible": true, + "comments": "", + "width": 30.000000000000004, + "height": 30.000000000000004, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorTextOn": "auto", + "label": "L", + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": true + }, + { + "type": "button", + "top": 50, + "left": 300, + "lock": false, + "id": "order_seed_lock", + "visible": true, + "comments": "", + "width": 29.999999999999996, + "height": 29.999999999999996, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorTextOn": "auto", + "label": "L", + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": true + }, + { + "type": "input", + "top": 50, + "left": 220, + "lock": false, + "id": "dur_seed", + "visible": true, + "interaction": true, + "comments": "", + "width": 80, + "height": 30.000000000000004, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "button", + "top": 50, + "left": 460, + "lock": false, + "id": "weights_seed_lock", + "visible": true, + "comments": "", + "width": 29.999999999999996, + "height": 29.999999999999996, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorTextOn": "auto", + "label": "L", + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": true + }, + { + "type": "input", + "top": 50, + "left": 380, + "lock": false, + "id": "weights_seed", + "visible": true, + "interaction": true, + "comments": "", + "width": 80, + "height": 30.000000000000004, + "expand": false, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + } + ], + "tabs": [] + } + ], + "tabs": [] + } +} \ No newline at end of file diff --git a/resources/314491/314491_code.scd b/resources/314491/314491_code.scd new file mode 100644 index 0000000..2d77a32 --- /dev/null +++ b/resources/314491/314491_code.scd @@ -0,0 +1,581 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrder, genSubMotif, updateVoices; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var writeResources, prettifyArray, setSeeds, sanityCheck, msgInterpret; + +// global vars (many set by OSC funcs at bottom) +var refSeed, seed, lastXChanges, popSize, exPath, dir, primes, dims, tuples, ranges, durFunc, seq, group, player; + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genOrder = {arg minLength = 0, maxLength = 5; + var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order; + noProgIns = (popSize - 1).rand + 1; + noSusIns = (popSize - noProgIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxLength - minLength).rand + minLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = [1, 1, 1, 1, 1]; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, res, lastIns, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + lastIns = nil; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + (silent ++ sus ++ prog).do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + //dur = [durFunc.value(), 0].wchoose([1, 0].normalizeSum); + dur = durFunc.value(lastIns, ins); + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur.round(0.125)]); + }); + + lastIns = ins; + }); + + // pad ending + if(isLastOrder, { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + //dur = [durFunc.value(), 0].wchoose([1, 0].normalizeSum); + dur = durFunc.value(lastIns, ins); + res = res.add([voices.deepCopy.postln, dur.round(0.125)]); + }); + lastIns = ins; + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = {arg inOrders; + var orders, repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + orders = inOrders; + + orders.do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +genPatterns = {arg seq; + var voices, durs, patterns, res; + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ); + }); + ); + res +}; + +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; + + +//------resource management funcs + +setSeeds = {arg inRefSeed, inSeed; + refSeed = if(inRefSeed.isNumber, {inRefSeed.asInteger}, {nil}); + seed = if(inSeed > 1, {inSeed.asInteger}, {rrand(100000, 999999)}); + thisThread.randSeed = seed; +}; + +prettifyArray = {arg data, finDepth = 1; + var prettyString = "", rCount = 0, writeArray; + + writeArray = {arg array; + var depth, indent; + depth = array.maxDepth; + indent = rCount.collect({" "}).join(""); + prettyString = prettyString ++ indent ++ "[\n"; + rCount = rCount + 1; + if(depth > 5, { + array.do({arg subArray; + writeArray.value(subArray); + }); + }, { + array.do({arg data, d; + prettyString = prettyString ++ indent ++ " " ++ data.asCompileString ++ if(d != (array.size - 1), {",\n"}, {""}); + }); + }); + rCount = rCount - 1; + if(rCount < (finDepth - 1), {prettyString = prettyString.drop((finDepth - 1).neg)}); + //if(rCount == 0, {prettyString = prettyString.drop((finDepth - 1).neg)}); + prettyString = prettyString ++ "\n" ++ indent ++ "]" ++ if(rCount > 0, {",\n"}, {""}); + }; + + writeArray.value(data); + prettyString +}; + +writeResources = {arg seq, path; + var dir, file, resString; + file = File(path,"w"); + + resString = "{\nmusic_data:\n"; + resString = resString ++ prettifyArray.value(seq, 3); + + resString = resString ++ ",\nlast_changes:\n"; + resString = resString ++ prettifyArray.value(lastXChanges, 1); + + resString = resString ++ ",\nseed: " ++ seed ++ ",\nref_seed: " ++ refSeed ++ "\n}"; + + file.write(resString); + file.close; +}; + +sanityCheck = {arg motif, index; + //print functions - very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in; + var res; + res = in.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + res = res.replace("\'", "").replace("\"", "").replace("Rest", "\"Rest\""); + res.interpret +}; + + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +refSeed = nil; +group = Group.new; + + +//------OSC funcs + +OSCdef(\gen, {arg msg, time, addr, port; + var orders, condition; + msg.postln; + durFunc = nil; + + addr.sendMsg("/STATE/SEND"); + + { + while({durFunc == nil}, {0.1.wait}); + setSeeds.value(msg[1].postln, msg[2]); + + lastXChanges = if(refSeed == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + file = File((dir +/+ "resources" +/+ refSeed ++ "_music" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + if(msg.size == 4, { + orders = msgInterpret.value(msg[3]); + }, { + var minLength, maxLength; + minLength = msg[3]; + maxLength = msg[4]; + orders = ((maxLength - minLength).rand + minLength).collect({genOrder.value(msg[5], msg[6])}); + }); + + orders.postln; + seed.postln; + refSeed.postln; + + seq = genMotif.value(orders); + //patterns = genPatterns.value(seq); + addr.sendMsg("/current_seed", seed); + addr.sendMsg("/order", prettifyArray.value(orders, 1)); + addr.sendMsg("/mus_seq", prettifyArray.value(seq, 3)); + }.fork; + +}, \gen); + +OSCdef(\commit, {arg msg, time, addr, port; + var ledgerPath, oldLedger, newLedger, musSeq; + //msg.postln; + seed.postln; + //File.copy(exPath, (dir +/+ "resources" +/+ seed ++ "_code" ++ ".scd").standardizePath); + //addr.sendMsg("/SESSION/SAVE", (dir +/+ "resources" +/+ seed ++ "_gui_session" ++ ".json").standardizePath); + //addr.sendMsg("/STATE/SAVE", (dir +/+ "resources" +/+ seed ++ "_gui_state" ++ ".state").standardizePath); + + writeResources.value(seq, (dir +/+ "resources" +/+ seed ++ "_music" ++ ".json").standardizePath); + + ledgerPath = (dir +/+ "resources" +/+ "piece_ledger" ++ ".json").standardizePath; + oldLedger = File(ledgerPath, "r"); + musSeq = msgInterpret.value(oldLedger.readAllString.parseJSON["ledger"]); + oldLedger.close; + File.delete(ledgerPath ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath, "w"); + musSeq = musSeq.add(seed); + newLedger.write("{\nledger:\n" ++ prettifyArray.value(musSeq, 1) ++ "\n}"); + newLedger.close; + + //refSeed = seed; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + var cSize, ledgerPath, ledger, patterns, pSeq; + ledgerPath = (dir +/+ "resources" +/+ "piece_ledger" ++ ".json").standardizePath; + ledger = msgInterpret.value(File(ledgerPath, "r").readAllString.parseJSON["ledger"]); + pSeq = []; + if(msg[2].asString != "all", {ledger = ledger.keep(msg[2].asInteger - 1)}); + ledger.do({arg rSeed; + var file; + file = File((dir +/+ "resources" +/+ rSeed.postln ++ "_music" ++ ".json").standardizePath, "r"); + pSeq = pSeq.add(msgInterpret.value(file.readAllString.parseJSON["music_data"])); + file.close; + }); + pSeq = pSeq.add(seq); + patterns = genPatterns.value(pSeq); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +OSCdef(\range, {arg msg; + msg.postln; + ranges[msg[1]][msg[2]] = msg[3] +}, \range); + +OSCdef(\dur_probs_env, {arg msg; + var env, pTable, min, max, cProb; + msg.postln; + env = Env.pairs([[0, 0]] ++ msg[4..].clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + min = msg[1]; + max = msg[2]; + cProb = msg[3]; + durFunc = {arg lIns, cIns; + if(lIns.postln == cIns.postln, { + pTable.tableRand * (max - min) + min + }, { + if(1.0.rand < cProb.postln, {0}, {pTable.tableRand * (max - min) + min}).postln; + }); + }; +}, \dur_probs_env); +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + +File((~dir +/+ "resources" +/+ 517313 ++ "_music" ++ ".json").standardizePath, "r").readAllString.parseJSON["last_changes"].asString.interpret[0][0][0].isNumber + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; \ No newline at end of file diff --git a/resources/314491/314491_gui_session.json b/resources/314491/314491_gui_session.json new file mode 100644 index 0000000..f0b1a0e --- /dev/null +++ b/resources/314491/314491_gui_session.json @@ -0,0 +1,1400 @@ +{ + "createdWith": "Open Stage Control", + "version": "1.22.0", + "type": "session", + "content": { + "type": "root", + "lock": false, + "id": "root", + "visible": true, + "interaction": true, + "comments": "", + "width": "auto", + "height": "auto", + "colorText": "auto", + "colorWidget": "auto", + "alphaFillOn": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "hideMenu": false, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "button", + "top": 460, + "left": 470, + "lock": false, + "id": "transport", + "visible": true, + "interaction": true, + "comments": "", + "width": 110, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorTextOn": "auto", + "label": "#{@{this} == 0 ? \"play\" : \"stop\"}", + "vertical": false, + "wrap": false, + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 0, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "if(value === 1){\n send(false, \"/transport\", 1, get(\"m_size\"));\n} else {\n send(false, \"/transport\", 0, get(\"m_size\"));\n}" + }, + { + "type": "button", + "top": 20, + "left": 470, + "lock": false, + "id": "gen", + "visible": true, + "interaction": true, + "comments": "", + "width": 290, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorTextOn": "auto", + "label": "generate", + "vertical": false, + "wrap": false, + "on": 1, + "off": 0, + "mode": "push", + "doubleTap": false, + "decoupled": false, + "value": "", + "default": 0, + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "if(value === 1){\n var sVal = 1\n var order = null\n var passage = null\n var rVal = get(\"reference_seed\")\n \n if(get(\"current_seed_lock\") == 1){\n sVal = get(\"seed\")\n } else {\n sVal = 1\n }\n \n if(get(\"order_lock\") == 1){\n order = get(\"order\").replace(/\\s/g, \"\")\n send(false, \"/gen\", rVal, sVal, order)\n } else {\n order = get(\"order_size\")\n passage = get(\"passage_size\")\n send(false, \"/gen\", rVal, sVal, \n {\"type\": \"i\", \"value\": order[0]}, \n {\"type\": \"i\", \"value\": order[1]}, \n {\"type\": \"i\", \"value\": passage[0]}, \n {\"type\": \"i\", \"value\": passage[1]});\n }\n\n}" + }, + { + "type": "matrix", + "top": 60, + "left": 120, + "lock": false, + "id": "range_matrix", + "visible": true, + "interaction": true, + "comments": "", + "width": 330, + "height": 260, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "horizontal", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "widgetType": "fragment", + "quantity": 4, + "props": "{\n \"file\": \"range_slider.json\",\n \"props\": {\"variables\": {\"n\": #{$} }}\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "widgets": [], + "tabs": [] + }, + { + "type": "input", + "top": 110, + "left": 590, + "lock": false, + "id": "current_seed", + "visible": true, + "interaction": true, + "comments": "", + "width": 130, + "height": "auto", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 0, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "", + "align": "center", + "unit": "", + "asYouType": true, + "numeric": true, + "validation": "", + "maxLength": "" + }, + { + "type": "button", + "top": 110, + "left": 730, + "lock": false, + "id": "current_seed_lock", + "visible": true, + "interaction": true, + "comments": "", + "width": 30, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorTextOn": "auto", + "label": "L", + "vertical": false, + "wrap": false, + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "" + }, + { + "type": "button", + "top": 500, + "left": 470, + "lock": false, + "id": "commit", + "visible": true, + "interaction": true, + "comments": "", + "width": 110, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "", + "default": 0, + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": true, + "onCreate": "", + "onValue": "if(value === 1){\n send(false, \"/commit\");\n set(\"reference_seed\", get(\"current_seed\"))\n set(\"current_seed\", \"\")\n}\n ", + "colorTextOn": "auto", + "label": "auto", + "vertical": false, + "wrap": false, + "on": 1, + "off": 0, + "mode": "push", + "doubleTap": false, + "decoupled": false + }, + { + "type": "textarea", + "top": 290, + "left": 470, + "lock": false, + "id": "order", + "visible": true, + "interaction": true, + "comments": "", + "width": 250, + "height": 140, + "expand": false, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "textarea {\n white-space: pre;\n line-height: 1.5;\n font-size: 12px;\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "s", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "button", + "top": 400, + "left": 730, + "lock": false, + "id": "order_lock", + "visible": true, + "comments": "", + "width": 30, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorTextOn": "auto", + "label": "L", + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": false + }, + { + "type": "text", + "top": 110, + "left": 470, + "lock": false, + "id": "current_seed_label", + "visible": true, + "comments": "", + "width": 110, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "current seed", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "vertical": false, + "wrap": false + }, + { + "type": "input", + "top": 60, + "left": 590, + "lock": false, + "id": "reference_seed", + "visible": true, + "comments": "", + "width": 130, + "height": "auto", + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "", + "default": "nil", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "unit": "", + "asYouType": true, + "numeric": true, + "validation": "", + "maxLength": "", + "typeTags": "", + "ignoreDefaults": false, + "bypass": true + }, + { + "type": "text", + "top": 60, + "left": 470, + "lock": false, + "id": "reference_seed_label", + "visible": true, + "comments": "", + "width": 110, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "value": "reference seed", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "align": "center" + }, + { + "type": "button", + "top": 60, + "left": 730, + "lock": false, + "id": "reference_seed_lock", + "visible": true, + "comments": "", + "width": 30, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "colorTextOn": "auto", + "label": "L", + "on": 1, + "off": 0, + "mode": "toggle", + "doubleTap": false, + "decoupled": false, + "typeTags": "", + "ignoreDefaults": false, + "bypass": true + }, + { + "type": "text", + "top": 20, + "left": 120, + "lock": false, + "id": "range_label", + "visible": true, + "comments": "", + "width": 110, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "align": "center", + "value": "ranges", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "" + }, + { + "type": "text", + "top": 160, + "left": 470, + "lock": false, + "id": "orders_label", + "visible": true, + "comments": "", + "width": 110, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "align": "center", + "value": "orders", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "" + }, + { + "type": "text", + "top": 340, + "left": 120, + "lock": false, + "id": "dur_probs_label", + "visible": true, + "comments": "", + "width": 110, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "duration probs", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "vertical": false, + "wrap": false + }, + { + "type": "input", + "top": 460, + "left": 590, + "lock": false, + "id": "m_size", + "visible": true, + "comments": "", + "width": 50, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "", + "default": 3, + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "", + "interaction": true, + "typeTags": "", + "ignoreDefaults": false, + "bypass": true, + "unit": "", + "asYouType": true, + "numeric": false, + "validation": "", + "maxLength": "" + }, + { + "type": "text", + "top": 460, + "left": 650, + "lock": false, + "id": "play_label", + "visible": true, + "comments": "", + "width": 110, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "value": "motifs to play", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "", + "align": "center", + "vertical": false, + "wrap": false + }, + { + "type": "panel", + "top": 380, + "left": 120, + "lock": false, + "id": "dur_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": 330, + "height": 260, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [], + "tabs": [ + { + "type": "tab", + "lock": false, + "id": "entrances", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "label": "auto", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [], + "tabs": [] + }, + { + "type": "tab", + "lock": false, + "id": "passage", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "label": "auto", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "fragment", + "top": 0, + "left": 0, + "lock": false, + "id": "dur", + "visible": true, + "interaction": true, + "comments": "", + "width": 320, + "height": 210, + "expand": "false", + "css": "", + "file": "env.json", + "fallback": "", + "props": {}, + "address": "auto", + "variables": "@{parent.variables}" + } + ], + "tabs": [] + }, + { + "type": "tab", + "lock": false, + "id": "exits", + "visible": true, + "interaction": true, + "comments": "", + "colorText": "auto", + "colorWidget": "auto", + "colorFill": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "label": "auto", + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [], + "tabs": [] + } + ], + "verticalTabs": false + }, + { + "type": "panel", + "top": 200, + "left": 470, + "lock": false, + "id": "order_size_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": 250, + "height": 40, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "range", + "top": 0, + "left": 40, + "lock": false, + "id": "order_size", + "visible": true, + "interaction": true, + "comments": "", + "width": 160, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "design": "default", + "knobSize": "auto", + "horizontal": true, + "pips": false, + "dashed": false, + "gradient": [], + "snap": true, + "spring": false, + "doubleTap": false, + "range": { + "min": 1, + "max": 10 + }, + "logScale": false, + "sensitivity": 1, + "steps": 10, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "i", + "decimals": 0, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "onTouch": "" + }, + { + "type": "input", + "top": 0, + "left": 200, + "lock": false, + "id": "order_size_v2", + "visible": true, + "comments": "", + "width": 40, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "@{order_size.value.1}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "set(\"order_size\", [get(\"order_size_v1\"), value])", + "interaction": true, + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "typeTags": "i", + "ignoreDefaults": false, + "bypass": false + }, + { + "type": "input", + "top": 0, + "left": 0, + "lock": false, + "id": "order_size_v1", + "visible": true, + "comments": "", + "width": 40, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "@{order_size.value.0}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "set(\"order_size\", [value, get(\"order_size_v2\")])", + "interaction": true, + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "typeTags": "i", + "ignoreDefaults": false, + "bypass": false + } + ], + "tabs": [] + }, + { + "type": "textarea", + "top": 60, + "left": 780, + "lock": false, + "id": "mus_seq", + "visible": true, + "interaction": true, + "comments": "", + "width": 520, + "height": 570, + "expand": false, + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "textarea {\n white-space: pre;\n line-height: 1.5;\n font-size: 12px;\n}", + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "s", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "" + }, + { + "type": "text", + "top": 20, + "left": 780, + "lock": false, + "id": "motif_label", + "visible": true, + "comments": "", + "width": 110, + "height": 33.888888888888886, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "vertical": false, + "wrap": false, + "align": "center", + "value": "motif", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 2, + "target": "", + "onCreate": "", + "onValue": "" + }, + { + "type": "panel", + "top": 240, + "left": 470, + "lock": false, + "id": "passage_size_panel", + "visible": true, + "interaction": true, + "comments": "", + "width": 250, + "height": 40, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "colorBg": "auto", + "layout": "default", + "justify": "start", + "gridTemplate": "", + "contain": true, + "scroll": true, + "innerPadding": true, + "verticalTabs": false, + "variables": "@{parent.variables}", + "traversing": false, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 2, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "widgets": [ + { + "type": "range", + "top": 0, + "left": 40, + "lock": false, + "id": "passage_size", + "visible": true, + "interaction": true, + "comments": "", + "width": 160, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "design": "default", + "knobSize": "auto", + "horizontal": true, + "pips": false, + "dashed": false, + "gradient": [], + "snap": true, + "spring": false, + "doubleTap": false, + "range": { + "min": 0, + "max": 10 + }, + "logScale": false, + "sensitivity": 1, + "steps": 11, + "value": "", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "typeTags": "", + "decimals": 0, + "target": "", + "ignoreDefaults": false, + "bypass": false, + "onCreate": "", + "onValue": "", + "onTouch": "" + }, + { + "type": "input", + "top": 0, + "left": 200, + "lock": false, + "id": "passage_size_v2", + "visible": true, + "comments": "", + "width": 40, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "@{passage_size.value.1}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "set(\"passage_size\", [get(\"passage_size_v1\"), value])", + "interaction": true, + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "typeTags": "", + "ignoreDefaults": false, + "bypass": false + }, + { + "type": "input", + "top": 0, + "left": 0, + "lock": false, + "id": "passage_size_v1", + "visible": true, + "comments": "", + "width": 40, + "height": 30, + "expand": "false", + "colorText": "auto", + "colorWidget": "auto", + "colorStroke": "auto", + "colorFill": "auto", + "alphaStroke": "auto", + "alphaFillOff": "auto", + "alphaFillOn": "auto", + "lineWidth": "auto", + "borderRadius": "auto", + "padding": "auto", + "html": "", + "css": "", + "align": "center", + "value": "@{passage_size.value.0}", + "default": "", + "linkId": "", + "address": "auto", + "preArgs": "", + "decimals": 0, + "target": "", + "onCreate": "", + "onValue": "set(\"passage_size\", [value, get(\"passage_size_v2\")])", + "interaction": true, + "unit": "", + "asYouType": false, + "numeric": false, + "validation": "", + "maxLength": "", + "typeTags": "", + "ignoreDefaults": false, + "bypass": false + } + ], + "tabs": [] + } + ], + "tabs": [] + } +} \ No newline at end of file diff --git a/resources/314491/314491_gui_state.state b/resources/314491/314491_gui_state.state new file mode 100644 index 0000000..e251d50 --- /dev/null +++ b/resources/314491/314491_gui_state.state @@ -0,0 +1,177 @@ +{ + "transport": 0, + "rangeslider_0_v1": -837.209302325582, + "rangeslider_0": [ + -837.209302325582, + 1227.9069767441865 + ], + "rangeslider_0_v2": 1227.9069767441865, + "range_panel": -1, + "rangeslider_1_v1": -613.953488372093, + "rangeslider_1": [ + -613.953488372093, + 1395.348837209302 + ], + "rangeslider_1_v2": 1395.348837209302, + "rangeslider_2_v1": -1116.279069767442, + "rangeslider_2": [ + -1116.279069767442, + 753.4883720930229 + ], + "rangeslider_2_v2": 753.4883720930229, + "rangeslider_3_v1": -725.5813953488375, + "rangeslider_3": [ + -725.5813953488375, + 976.7441860465119 + ], + "rangeslider_3_v2": 976.7441860465119, + "range_matrix": [ + null, + null, + null, + null + ], + "current_seed": 314491, + "current_seed_lock": 1, + "commit": 0, + "order_lock": 0, + "current_seed_label": "current seed", + "reference_seed": "nil", + "reference_seed_label": "reference seed", + "reference_seed_lock": 1, + "range_label": "ranges", + "orders_label": "orders", + "dur_probs_label": "duration probs", + "m_size": 1, + "play_label": "motifs to play", + "entrances": [ + 0, + 0 + ], + "dur_probs_size": 3, + "dur_probs_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.5, + 0.5 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "dur_probs_slider": [ + 0.6147540983606558, + 1.51639344262295 + ], + "dur_probs_rslider_v2": 1.51639344262295, + "dur_probs_rslider_v1": 0.6147540983606558, + "dur_probs_mpos": "", + "dur_probs_env": [ + 0.6147540983606558, + 1.51639344262295, + 0, + 0, + 0.5, + 0.5, + 0.5, + 1, + 0.5 + ], + "dur_probs_flatten": 0, + "dur_probs_chord_prob": 0, + "text_1": "chord prob", + "dur_probs": -1, + "passage": -1, + "exits": [ + 0, + 0 + ], + "order_size": [ + 2, + 6 + ], + "order_size_v2": 6, + "order_size_v1": 2, + "order_size_panel": -1, + "motif_label": "motif", + "passage_size": [ + 8, + 10 + ], + "passage_size_v2": 10, + "passage_size_v1": 8, + "passage_size_panel": -1, + "root": [ + 0, + 0 + ], + "mus_seq": "[\n [\n [\n [ [ [ 0, 0, 0, 0, 0, 0 ], [ \"Rest\" ], [ \"Rest\" ], [ \"Rest\" ] ], 0.875 ],\n [ [ [ 0, 0, 0, 0, 0, 0 ], [ \"Rest\" ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.625 ],\n [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.5 ],\n [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ],\n [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ],\n [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0 ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.0 ],\n [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 1, 0, 0 ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.0 ],\n [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, 0 ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.25 ],\n [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ],\n [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ],\n [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.25 ],\n [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.75 ]\n ],\n [\n [ [ [ 0, 0, 0, 0, 0, 0 ], [ \"Rest\" ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ],\n [ [ [ 1, 0, 0, 0, 0, -1 ], [ \"Rest\" ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.5 ],\n [ [ [ 1, 0, 0, 0, 0, -1 ], [ \"Rest\" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.25 ],\n [ [ [ 0, 1, 0, 0, 0, 0 ], [ \"Rest\" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.375 ],\n [ [ [ 0, 0, 0, 1, 0, 0 ], [ \"Rest\" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.75 ],\n [ [ [ 0, 0, 0, 1, 0, 0 ], [ \"Rest\" ], [ 0, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.625 ],\n [ [ [ 0, 0, 0, 1, 0, 0 ], [ \"Rest\" ], [ 0, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.75 ],\n [ [ [ 0, 0, 0, 0, 0, 1 ], [ \"Rest\" ], [ 0, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.125 ],\n [ [ [ 1, 0, -1, 0, 0, 0 ], [ \"Rest\" ], [ 0, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.25 ],\n [ [ [ 0, 1, 0, 0, 0, 0 ], [ \"Rest\" ], [ 0, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.0 ],\n [ [ [ 1, -1, 0, 0, 0, 0 ], [ \"Rest\" ], [ 0, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ]\n ],\n [\n [ [ [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, -1, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ],\n [ [ [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, -1, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ] ], 0.75 ],\n [ [ [ 0, 0, 0, 1, -1, 0 ], [ 1, 0, -1, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ] ], 1.5 ],\n [ [ [ 0, 0, 0, 1, -1, 0 ], [ 0, 0, 0, 0, -1, 1 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ] ], 1.25 ],\n [ [ [ 0, 0, 0, 1, -1, 0 ], [ 0, 1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ] ], 0.625 ],\n [ [ [ 1, 0, 0, 0, -1, 0 ], [ 0, 1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ] ], 0.625 ],\n [ [ [ 1, 0, 0, 0, -1, 0 ], [ 0, 1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 0, 0, 1, 0, -1, 0 ] ], 0.625 ],\n [ [ [ 1, 0, 0, 0, -1, 0 ], [ 0, 1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, 0, 0, -1, -1, 0 ] ], 1.375 ],\n [ [ [ 1, 0, 0, 0, -1, 0 ], [ 0, 0, 1, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, 0, 0, -1, -1, 0 ] ], 1.375 ],\n [ [ [ 2, 0, 0, -1, -1, 0 ], [ 0, 0, 1, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, 0, 0, -1, -1, 0 ] ], 1.5 ],\n [ [ [ 2, 0, 0, 0, -1, -1 ], [ 0, 0, 1, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, 0, 0, -1, -1, 0 ] ], 0.75 ],\n [ [ [ 2, 0, 0, 0, -1, -1 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, 0, 0, -1, -1, 0 ] ], 1.0 ]\n ],\n [\n [ [ [ 2, 0, 0, 0, -1, -1 ], [ 1, -1, 0, 0, -1, 0 ], [ \"Rest\" ], [ 1, 0, 0, -1, -1, 0 ] ], 0.75 ],\n [ [ [ 2, 0, 0, 0, -1, -1 ], [ 1, -1, 0, 0, -1, 0 ], [ \"Rest\" ], [ 0, -1, 0, 1, -1, 0 ] ], 1.0 ],\n [ [ [ 2, -1, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ \"Rest\" ], [ 0, -1, 0, 1, -1, 0 ] ], 0.875 ],\n [ [ [ 2, -1, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ \"Rest\" ], [ 0, -1, 0, 0, -1, 1 ] ], 1.25 ],\n [ [ [ 1, -1, 0, 1, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ \"Rest\" ], [ 0, -1, 0, 0, -1, 1 ] ], 1.125 ],\n [ [ [ 1, -1, 0, 1, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ \"Rest\" ], [ 1, -1, -1, 0, -1, 0 ] ], 1.0 ],\n [ [ [ 1, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ \"Rest\" ], [ 1, -1, -1, 0, -1, 0 ] ], 0.75 ],\n [ [ [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ \"Rest\" ], [ 1, -1, -1, 0, -1, 0 ] ], 0.625 ],\n [ [ [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ \"Rest\" ], [ 0, -1, 0, 0, 0, 0 ] ], 0.75 ],\n [ [ [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ \"Rest\" ], [ 1, -1, 0, 0, -2, 0 ] ], 1.375 ],\n [ [ [ 2, -2, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ \"Rest\" ], [ 1, -1, 0, 0, -2, 0 ] ], 0.875 ],\n [ [ [ 2, -2, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ \"Rest\" ], [ 0, -1, 0, 0, -1, 1 ] ], 1.375 ],\n [ [ [ 2, -2, 0, 0, -1, 0 ], [ \"Rest\" ], [ \"Rest\" ], [ 0, -1, 0, 0, -1, 1 ] ], 1.5 ],\n [ [ [ \"Rest\" ], [ \"Rest\" ], [ \"Rest\" ], [ 0, -1, 0, 0, -1, 1 ] ], 1.375 ],\n [ [ [ \"Rest\" ], [ \"Rest\" ], [ \"Rest\" ], [ \"Rest\" ] ], 1.0 ]\n ]\n ]\n]", + "order": "[\n [ [ 0, 3 ], [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], [ 2 ] ],\n [ [ 3 ], [ 0, 2, 0, 0, 2, 2, 0, 0, 0, 0 ], [ 1 ] ],\n [ [ 2 ], [ 1, 3, 0, 1, 1, 0, 3, 3, 1, 0, 0, 1 ], [ ] ],\n [ [ 1 ], [ 3, 0, 3, 0, 3, 0, 0, 3, 3, 0, 3 ], [ 2 ] ]\n]", + "dur_panel": 1, + "gen": 0 +} \ No newline at end of file diff --git a/resources/314491/314491_music.json b/resources/314491/314491_music.json new file mode 100644 index 0000000..ef5284d --- /dev/null +++ b/resources/314491/314491_music.json @@ -0,0 +1,75 @@ +{ +music_data: +[ + [ + [ + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 0.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.625 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.5 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.0 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 1, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.0 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.25 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.25 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.75 ] + ], + [ + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ], + [ [ [ 1, 0, 0, 0, 0, -1 ], [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.5 ], + [ [ [ 1, 0, 0, 0, 0, -1 ], [ "Rest" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.25 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ "Rest" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.375 ], + [ [ [ 0, 0, 0, 1, 0, 0 ], [ "Rest" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.75 ], + [ [ [ 0, 0, 0, 1, 0, 0 ], [ "Rest" ], [ 0, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.625 ], + [ [ [ 0, 0, 0, 1, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.75 ], + [ [ [ 0, 0, 0, 0, 0, 1 ], [ "Rest" ], [ 0, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.125 ], + [ [ [ 1, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.25 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.0 ], + [ [ [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ] + ], + [ + [ [ [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, -1, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ], + [ [ [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, -1, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ] ], 0.75 ], + [ [ [ 0, 0, 0, 1, -1, 0 ], [ 1, 0, -1, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ] ], 1.5 ], + [ [ [ 0, 0, 0, 1, -1, 0 ], [ 0, 0, 0, 0, -1, 1 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ] ], 1.25 ], + [ [ [ 0, 0, 0, 1, -1, 0 ], [ 0, 1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ] ], 0.625 ], + [ [ [ 1, 0, 0, 0, -1, 0 ], [ 0, 1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ] ], 0.625 ], + [ [ [ 1, 0, 0, 0, -1, 0 ], [ 0, 1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 0, 0, 1, 0, -1, 0 ] ], 0.625 ], + [ [ [ 1, 0, 0, 0, -1, 0 ], [ 0, 1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, 0, 0, -1, -1, 0 ] ], 1.375 ], + [ [ [ 1, 0, 0, 0, -1, 0 ], [ 0, 0, 1, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, 0, 0, -1, -1, 0 ] ], 1.375 ], + [ [ [ 2, 0, 0, -1, -1, 0 ], [ 0, 0, 1, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, 0, 0, -1, -1, 0 ] ], 1.5 ], + [ [ [ 2, 0, 0, 0, -1, -1 ], [ 0, 0, 1, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, 0, 0, -1, -1, 0 ] ], 0.75 ], + [ [ [ 2, 0, 0, 0, -1, -1 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, 0, 0, -1, -1, 0 ] ], 1.0 ] + ], + [ + [ [ [ 2, 0, 0, 0, -1, -1 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 1, 0, 0, -1, -1, 0 ] ], 0.75 ], + [ [ [ 2, 0, 0, 0, -1, -1 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 0, -1, 0, 1, -1, 0 ] ], 1.0 ], + [ [ [ 2, -1, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 0, -1, 0, 1, -1, 0 ] ], 0.875 ], + [ [ [ 2, -1, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 0, -1, 0, 0, -1, 1 ] ], 1.25 ], + [ [ [ 1, -1, 0, 1, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 0, -1, 0, 0, -1, 1 ] ], 1.125 ], + [ [ [ 1, -1, 0, 1, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 1, -1, -1, 0, -1, 0 ] ], 1.0 ], + [ [ [ 1, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 1, -1, -1, 0, -1, 0 ] ], 0.75 ], + [ [ [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 1, -1, -1, 0, -1, 0 ] ], 0.625 ], + [ [ [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 0, -1, 0, 0, 0, 0 ] ], 0.75 ], + [ [ [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 1, -1, 0, 0, -2, 0 ] ], 1.375 ], + [ [ [ 2, -2, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 1, -1, 0, 0, -2, 0 ] ], 0.875 ], + [ [ [ 2, -2, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 0, -1, 0, 0, -1, 1 ] ], 1.375 ], + [ [ [ 2, -2, 0, 0, -1, 0 ], [ "Rest" ], [ "Rest" ], [ 0, -1, 0, 0, -1, 1 ] ], 1.5 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ 0, -1, 0, 0, -1, 1 ] ], 1.375 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 1.0 ] + ] + ] +], +last_changes: +[ + [ [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, -1, 0, -1, 0 ] ], + [ [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], + [ [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ] ], + [ [ 2, -2, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ] ], + [ [ 2, -2, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 0, -1, 0, 0, -1, 1 ] ] +], +seed: 314491, +ref_seed: nil +} \ No newline at end of file diff --git a/resources/46b6952a/46b6952a_code.scd b/resources/46b6952a/46b6952a_code.scd new file mode 100644 index 0000000..65c17df --- /dev/null +++ b/resources/46b6952a/46b6952a_code.scd @@ -0,0 +1,719 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck, +msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON; + +// model vars +//(model and global vars mostly set by OSC funcs +var curUID, refUID, orderSeed, durSeed, motifSeed, +entrancesProbVals, passagesProbVals, exitsProbVals, +ranges, orders, susWeights, passagesWeights, passagesSize, orderSize; + +// model aux vars +var entrancesDurFunc, passagesDurFunc, exitsDurFunc; + +// other global vars +var lastXChanges, popSize, exPath, dir, primes, dims, tuples, +seq, group, player, ledgerPath, ledger, currentlyPlayingUID; + + +// install JSON quark +if(Quarks.isInstalled("JSONlib").not, { + Quarks.install("https://github.com/musikinformatik/JSONlib.git"); + thisProcess.recompile; + //HelpBrowser.openHelpFor("Classes/JSONlib"); +}); + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genDurFunc = {arg chordProb, min, max, envData; + var env, pTable, durFunc; + env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + durFunc = {arg allowChord; + var res; + res = if(allowChord.not, { + pTable.tableRand * (max - min) + min + }, { + if(1.0.rand < chordProb, {0}, {pTable.tableRand * (max - min) + min}); + }).round(0.125); + if(res.asInteger == res, {res = res.asInteger}); + res + }; + seedFunc.value(durFunc, durSeed); +}; + +genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5; + ((maxMotifLength - minMotifLength).rand + minMotifLength).collect({ + var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order; + noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum); + noProgIns = (popSize - noSusIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] + }); +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = passagesWeights; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, flatOrder, res, isInChord, allowChord, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + flatOrder = silent ++ sus ++ prog; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + isInChord = popSize.collect({false}); + allowChord = false; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + flatOrder.do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + allowChord = if((sus ++ silent).includes(ins), { + (sus ++ silent).includes(ins) && (ins != sus.last); + }, { + if(i < (flatOrder.size - 1), {(isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not}, {false}); + }); + dur = passagesDurFunc.value(allowChord); + if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})}); + + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + + // pad ending + if(isLastOrder, { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + allowChord = (voices != popSize.collect({["Rest"]})); + dur = passagesDurFunc.value(allowChord); + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = { + var repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + + orders.do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~addr.sendMsg(~indexPath, ~indexMsg); + ~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3)); + //~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln); + }; +}); + +genPatterns = {arg inSeq, addr; + var voices, durs, patterns, res, indices, sectionDurs, ids, seq; + seq = inSeq.collect({arg mSeq; mSeq[0]}); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + indices = inSeq.collect({arg mSeq, m; mSeq[1]}); + ids = inSeq.collect({arg mSeq, m; mSeq[2]}); + sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum}); + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ) + }) ++ + [ + Pbind( + \type, \osc, + \addr, addr, + \indexPath, "/cur_play_index", + \indexMsg, Pseq(indices.postln, 1), + \seqPath, "/mus_seq", + \seqMsg, Pseq(seq, 1), + \dur, Pseq(sectionDurs, 1) + ); + ] + ); + res +}; + +/* +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; +*/ + + +//------resource management funcs + +genUID = {Date.seed.asHexString.toLower}; + +seedFunc = {arg func, seed; + var funcArgs, next; + next = Routine({loop{func.valueArray(funcArgs).yield }}); + next.randSeed_(seed); + {arg ...args; funcArgs = args; next.value} +}; + +stringifyToDepth = {arg data, maxDepth = 1; + var prettyString = "", rCount = 0, writeArray, indent; + + if(maxDepth == 0, { + data.asCompileString + }, { + indent = {arg size; size.collect({" "}).join("")}; + writeArray = {arg array; + prettyString = prettyString ++ indent.value(rCount) ++ "[\n"; + rCount = rCount + 1; + if(rCount < (maxDepth - 0), { + array.do({arg subArray; writeArray.value(subArray)}); + }, { + prettyString = prettyString ++ array.collect({arg subArray; + indent.value(rCount + 1) ++ subArray.asCompileString + }).join(",\n"); + }); + rCount = rCount - 1; + prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n"; + }; + + writeArray.value(data); + prettyString.replace(",\n\n", "\n").drop(-2); + }) +}; + +sanityCheck = {arg motif, index; + //print functions = very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true; + var res; + + res = in; + if(res.isNil.not, { + if((res.isArray && res.isString.not), { + res = res.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + if(escapeSingleQuotes, {res = res.replace("\'", "")}); + if(escapeDoubleQuotes, {res = res.replace("\"", "")}); + res = res.replace("Rest", "\"Rest\""); + res = res.interpret; + }, { + //res.postln; + if(res.every({arg char; char.isDecDigit}), {res = res.asInteger}); + }); + }); + res +}; + +writeResources = {arg path; + var file, nameSpaces, modelItems, resString; + file = File(path,"w"); + + nameSpaces = [ + "music_data", "last_changes", + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + modelItems = [ + seq, lastXChanges, + curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize + ]; + + resString = [nameSpaces, modelItems].flop.collect({arg item; + var nameSpace, modelItem, depth = 0, insert = " "; + # nameSpace, modelItem = item; + if(nameSpace == "music_data", {depth = 3; insert = "\n"}); + if(nameSpace == "last_changes", {depth = 1; insert = "\n"}); + if(nameSpace == "order", {depth = 1; insert = "\n"}); + "\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem.postln, depth).postln + }).join(",\n"); + + resString = "{\n" ++ resString ++ "\n}"; + + file.write(resString); + file.close; +}; + +loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)}; + +loadModelJSON = {arg model; + var nameSpaces, data; + + //model = File(path, "r").readAllString.parseJSON; + + nameSpaces = [ + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + data = nameSpaces.collect({arg nS; msgInterpret.value(model[nS]).postln}); + + data.postln; + + # curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize = data; + + popSize = ranges.size; +}; + +loadLedgerFile = {arg path; + ledgerPath = path; + loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON) +}; + +loadLedgerJSON = {arg ledger; ledger = ledger["ledger"]}; + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +//popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +//refUID = nil; +group = Group.new; +loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json"); +//passagesWeights = [1, 1, 1, 1, 1]; +//susWeights = [1, 1, 1]; + + +//------OSC funcs + +OSCdef(\load_ledger, {arg msg, time, addr, port; + loadLedgerFile.value(msg[1].asString); +}, \load_ledger); + +OSCdef(\load_model, {arg msg, time, addr, port; + loadModelFile.value(msg[1].asString); +}, \load_model); + + +OSCdef(\generate, {arg msg, time, addr, port; + var path, dFormat, condition, musPath; + msg.postln; + + path = msg[1].asString; + + loadModelFile.value(path); + + refUID.postln; + + loadLedgerFile.value(ledgerPath); + if(ledger == nil, {ledger = ["tmp"]}); + if(ledger.last != "tmp", {ledger = ledger.add("tmp")}); + + lastXChanges = if(refUID == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + refUID.postln; + file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..2] ++ [entrancesProbVals[3..]]); + passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..2] ++ [passagesProbVals[3..]]); + exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..2] ++ [exitsProbVals[3..]]); + + if(orders == nil, { + orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize); + addr.sendMsg("/order", stringifyToDepth.value(orders, 1)); + }); + seq = seedFunc.value(genMotif, motifSeed).value; + + //musPath = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath; + writeResources.value(path); + + //orders = nil; + //addr.sendMsg("/current_uid", curUID); + //addr.sendMsg("/ledger", prettifyArray.value(ledger, 1).replace("\"", "")); + //addr.sendMsg("/ledger_size", ledger.size); + //addr.sendMsg("/mus_seq", prettifyArray.value(seq, 3)); + addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3)); +}, \generate); + + +OSCdef(\commit, {arg msg, time, addr, port; + var newLedger, modelPath, musString, musFile, test1, test2; + msg.postln; + + /* + test1 = msg[1].asString.parseJSON; + test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile; + msgInterpret.value(test1["music"])[0][0][0][1].class.postln; + msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln; + (test1["music"] == test2["music_data"]).postln; + */ + + curUID = genUID.value; + File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath); + File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath); + + modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; + writeResources.value(modelPath); + + File.delete(ledgerPath.postln ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath.postln, "w"); + ledger = ledger.postln.drop(-1).add(curUID); + newLedger.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}"); + newLedger.close; + + addr.sendMsg("/committed", curUID, ledgerPath); + //refUID = curUID; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + // the cued sequence can now be read from file, so this can be cleaned up + var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; + pSeq = []; + cuedSeek = (seq != nil); + indexStart = msg[2].asInteger; + indexEnd = ledger.size - if(cuedSeek, {2}, {1}); + if(((indexStart == (ledger.size - 1)) && cuedSeek).not, { + ledger[indexStart..indexEnd].do({arg uid, index; + var file; + (indexStart + index).postln; + file = File((dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_music" ++ ".json").standardizePath, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), indexStart + index, uid]); + file.close; + }); + }); + if(cuedSeek, {pSeq = pSeq.add([seq, ledger.size - 1])}); + patterns = genPatterns.value(pSeq, addr); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; + +1223423434123.asHexString.toLower + +Date.getDate.rawSeconds +Date.seed.asHexString.toLower + +n = NetAddr("localhost", 8080); +n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals"); \ No newline at end of file diff --git a/resources/46b6952a/46b6952a_gui_state.json b/resources/46b6952a/46b6952a_gui_state.json new file mode 100644 index 0000000..ea5446c --- /dev/null +++ b/resources/46b6952a/46b6952a_gui_state.json @@ -0,0 +1,1359 @@ +{ + "motif_label": "motif", + "seeds_label": "seeds", + "order": "[\n [ [ 3, 1, 0 ], [ 2 ], [ ] ],\n [ [ 1, 2 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 3 ] ],\n [ [ 3, 2 ], [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], [ 0 ] ],\n [ [ 2, 3 ], [ 0, 1, 0 ], [ ] ]\n]", + "order_lock": 1, + "order_size": [ + 3, + 8 + ], + "order_size_v2": 8, + "order_size_v1": 3, + "order_size_panel": -1, + "passage_size_v2": 8, + "passage_size_v1": 2, + "passage_size_panel": -1, + "sus_weights": [ + null, + null, + null + ], + "range_matrix": [ + null, + null, + null, + null + ], + "instrumentation": [ + 0, + 0 + ], + "entrances_probs_sync": "passages", + "entrances": -1, + "passages_probs_sync": "passages", + "passages": -1, + "exits_probs_sync": "passages", + "exits": -1, + "dur_panel": 0, + "durations": -1, + "passages_weights": [ + null, + null, + null, + null, + null + ], + "weights": -1, + "seeds_tab_panel": 0, + "weights_seed_lock": 0, + "weights_seed": 534103, + "sus_weights/0_slider_val": 0.21, + "sus_weights/0_slider_slider": 0.21, + "sus_weights/0_slider_input": 0.21, + "sus_weights/0_slider_label": 1, + "sus_weights/0_slider": -1, + "sus_weights/1_slider_val": 0.35, + "sus_weights/1_slider_slider": 0.35, + "sus_weights/1_slider_input": 0.35, + "sus_weights/1_slider_label": 2, + "sus_weights/1_slider": -1, + "sus_weights/2_slider_val": 0.21, + "sus_weights/2_slider_slider": 0.21, + "sus_weights/2_slider_input": 0.21, + "sus_weights/2_slider_label": 3, + "sus_weights/2_slider": -1, + "passages_weights/0_slider_val": 0.49, + "passages_weights/0_slider_slider": 0.49, + "passages_weights/0_slider_input": 0.49, + "passages_weights/0_slider_label": "step", + "passages_weights/0_slider": -1, + "passages_weights/1_slider_val": 0.53, + "passages_weights/1_slider_slider": 0.53, + "passages_weights/1_slider_input": 0.53, + "passages_weights/1_slider_label": "dc", + "passages_weights/1_slider": -1, + "passages_weights/2_slider_val": 0.35, + "passages_weights/2_slider_slider": 0.35, + "passages_weights/2_slider_input": 0.35, + "passages_weights/2_slider_label": "range", + "passages_weights/2_slider": -1, + "passages_weights/3_slider_val": 0.59, + "passages_weights/3_slider_slider": 0.59, + "passages_weights/3_slider_input": 0.59, + "passages_weights/3_slider_label": "registration", + "passages_weights/3_slider": -1, + "passages_weights/4_slider_val": 0.39, + "passages_weights/4_slider_slider": 0.39, + "passages_weights/4_slider_input": 0.39, + "passages_weights/4_slider_label": "hd", + "passages_weights/4_slider": -1, + "range_matrix/0_val_input_min": -853.2067988668555, + "range_matrix/0_val_rslider": [ + -853.2067988668555, + 401 + ], + "range_matrix/0_val_input_max": 401, + "range_matrix/0_val": -1, + "range_matrix/1_val_input_min": -659, + "range_matrix/1_val_rslider": [ + -659, + 880 + ], + "range_matrix/1_val_input_max": 880, + "range_matrix/1_val": -1, + "range_matrix/2_val_input_min": -241, + "range_matrix/2_val_rslider": [ + -241, + 1869 + ], + "range_matrix/2_val_input_max": 1869, + "range_matrix/2_val": -1, + "range_matrix/3_val_input_min": -27, + "range_matrix/3_val_rslider": [ + -27, + 2063 + ], + "range_matrix/3_val_input_max": 2063, + "range_matrix/3_val": -1, + "entrances_probs_chord_slider_val": 0.66, + "entrances_probs_chord_slider_slider": 0.66, + "entrances_probs_chord_slider_input": 0.66, + "entrances_probs_chord_slider_label": "chord prob", + "entrances_probs_chord_slider": -1, + "entrances_probs_vals": [ + 0.63, + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.3963730569948187, + 0.8716216216216216, + 0.4948186528497409, + 0.5912162162162162, + 0.5362694300518135, + 0.8614864864864865, + 0.6424870466321243, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "entrances_probs": -1, + "passages_probs_chord_slider_val": 0.63, + "passages_probs_chord_slider_slider": 0.63, + "passages_probs_chord_slider_input": 0.63, + "passages_probs_chord_slider_label": "chord prob", + "passages_probs_chord_slider": -1, + "passages_probs_vals": [ + 0.63, + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.3963730569948187, + 0.8716216216216216, + 0.4948186528497409, + 0.5912162162162162, + 0.5362694300518135, + 0.8614864864864865, + 0.6424870466321243, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "passages_probs": -1, + "exits_probs_chord_slider_val": 0, + "exits_probs_chord_slider_slider": 0, + "exits_probs_chord_slider_input": 0, + "exits_probs_chord_slider_label": "chord prob", + "exits_probs_chord_slider": -1, + "exits_probs_vals": [ + 0, + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.4948186528497409, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "exits_probs": -1, + "step_env_env_vals": [ + 0, + 5, + 0, + 0, + 0, + 0, + 0.14609053497942387, + 0.7613636363636364, + 0.20164609053497942, + 0.26136363636363635, + 0.24279835390946503, + 0.7215909090909092, + 0.39094650205761317, + 0.875, + 0.4567901234567901, + 0.44318181818181823, + 0.5432098765432098, + 0.34659090909090906, + 0.6481481481481481, + 0.8011363636363636, + 0.6810699588477366, + 0.5170454545454546, + 0.8868312757201646, + 0.49431818181818177, + 0.8868312757201646, + 0.49431818181818177 + ], + "step_env_env_canvas": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0.14609053497942387, + 0.7613636363636364 + ], + [ + 0.20164609053497942, + 0.26136363636363635 + ], + [ + 0.24279835390946503, + 0.7215909090909092 + ], + [ + 0.39094650205761317, + 0.875 + ], + [ + 0.4567901234567901, + 0.44318181818181823 + ], + [ + 0.5432098765432098, + 0.34659090909090906 + ], + [ + 0.6481481481481481, + 0.8011363636363636 + ], + [ + 0.6810699588477366, + 0.5170454545454546 + ], + [ + 0.8868312757201646, + 0.49431818181818177 + ], + [ + 0.8868312757201646, + 0.49431818181818177 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "step_env_env_size": 12, + "step_env_env_flatten": 0, + "step_env_env_rslider": [ + 0, + 5 + ], + "step_env_env_rslider_v2": 5, + "step_env_env_rslider_v1": 0, + "step_env_env_mpos": "", + "step_env_env": -1, + "entrances_probs_dur_env_vals": [ + 0.515267175572519, + 4.599236641221374, + 0, + 0.5, + 0.2772020725388601, + 0.7972972972972973, + 0.45077720207253885, + 0.8783783783783784, + 0.5, + 0.5, + 0.727979274611399, + 0.45270270270270274, + 0.7357512953367875, + 0.6486486486486487, + 0.8911917098445595, + 0.7905405405405406, + 1, + 0.5 + ], + "entrances_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.2772020725388601, + 0.7972972972972973 + ], + [ + 0.45077720207253885, + 0.8783783783783784 + ], + [ + 0.5, + 0.5 + ], + [ + 0.727979274611399, + 0.45270270270270274 + ], + [ + 0.7357512953367875, + 0.6486486486486487 + ], + [ + 0.8911917098445595, + 0.7905405405405406 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "entrances_probs_dur_env_size": 8, + "entrances_probs_dur_env_flatten": 0, + "entrances_probs_dur_env_rslider": [ + 0.515267175572519, + 4.599236641221374 + ], + "entrances_probs_dur_env_rslider_v2": 4.599236641221374, + "entrances_probs_dur_env_rslider_v1": 0.515267175572519, + "entrances_probs_dur_env_mpos": "", + "entrances_probs_dur_env": -1, + "passages_probs_dur_env_vals": [ + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.3963730569948187, + 0.8716216216216216, + 0.4948186528497409, + 0.5912162162162162, + 0.5362694300518135, + 0.8614864864864865, + 0.6424870466321243, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "passages_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.23316062176165803, + 0.7094594594594594 + ], + [ + 0.3963730569948187, + 0.8716216216216216 + ], + [ + 0.4948186528497409, + 0.5912162162162162 + ], + [ + 0.5362694300518135, + 0.8614864864864865 + ], + [ + 0.6424870466321243, + 0.5912162162162162 + ], + [ + 0.7901554404145078, + 0.8277027027027027 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "passages_probs_dur_env_size": 8, + "passages_probs_dur_env_flatten": 0, + "passages_probs_dur_env_rslider": [ + 0, + 5 + ], + "passages_probs_dur_env_rslider_v2": 5, + "passages_probs_dur_env_rslider_v1": 0, + "passages_probs_dur_env_mpos": "", + "passages_probs_dur_env": -1, + "exits_probs_dur_env_vals": [ + 0, + 5, + 0, + 0.5, + 0.5, + 0.5, + 1, + 0.5 + ], + "exits_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.5, + 0.5 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "exits_probs_dur_env_size": 3, + "exits_probs_dur_env_flatten": 0, + "exits_probs_dur_env_rslider": [ + 0, + 5 + ], + "exits_probs_dur_env_rslider_v2": 5, + "exits_probs_dur_env_rslider_v1": 0, + "exits_probs_dur_env_mpos": "", + "exits_probs_dur_env": -1, + "mus_seq": [ + [ + [ + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + "Rest" + ], + [ + "Rest" + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + "Rest" + ] + ], + 1.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + 0, + 1, + -3, + 0, + 2, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.75 + ], + [ + [ + [ + 1, + 1, + -2, + -2, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.625 + ], + [ + [ + [ + 1, + 1, + -3, + -1, + 0, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.625 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ] + ], + [ + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -2, + 0, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.375 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 2, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -2, + -1, + 2, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 0, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.875 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1 + ] + ], + [ + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 2, + 0, + -3, + -1, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.625 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + "Rest" + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + "Rest" + ] + ], + 1.875 + ], + [ + [ + [ + "Rest" + ], + [ + "Rest" + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + "Rest" + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + "Rest" + ], + [ + "Rest" + ], + [ + "Rest" + ] + ], + 0.875 + ] + ] + ] + ], + "root": [ + 0.20743639921722112, + 0 + ], + "order_seed": 798574, + "dur_seed": 884869, + "passages_size": [ + 0, + 10 + ], + "dur_seed_lock": 1, + "order_seed_lock": 0, + "seeds_panel": -1, + "motif_panel": [ + 0, + 0 + ], + "ref_uid": "6f1a789f", + "cur_uid": "46b6952a" +} \ No newline at end of file diff --git a/resources/46b6952a/46b6952a_mus_model.json b/resources/46b6952a/46b6952a_mus_model.json new file mode 100644 index 0000000..024062b --- /dev/null +++ b/resources/46b6952a/46b6952a_mus_model.json @@ -0,0 +1,57 @@ +{ +"music_data": +[ + [ + [ + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 0 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ], [ 2, 0, 0, -1, 0, 0 ] ], 1.625 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 2, 0, 0, -2, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 0.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 0.625 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.625 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 1, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.25 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 2, 0, 0, -1, -1, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.375 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 1, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 2, -1, 0, 0, 0, -1 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.125 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 2, -2, 0, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.5 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.375 ] + ], + [ + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 0.5 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 2 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 0.625 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 0.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ "Rest" ], [ 2, 0, 0, -1, 0, 0 ] ], 0 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 2, 0, 0, -1, 0, 0 ] ], 0 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 0 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 0.75 ] + ] + ] +], +"last_changes": +[ + [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], + [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], + [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], + [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], + [ [ 0, 0, 0, 0, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ] +], +"cur_uid": "46b6952a", +"ref_uid": "7e170ef8", +"order_seed": 969134, +"dur_seed": 384656, +"motifs_seed": 435714, +"entrances_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ], +"passages_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"exits_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ], +"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ], +"order": +[ + [ [ 0, 1, 3 ], [ 2, 2, 2, 2, 2, 2, 2, 2, 2 ], [ ] ], + [ [ 0, 2, 3 ], [ 1, 1, 1, 1 ], [ ] ] +], +"sus_weights": [ 0.75, 0.69, 0.75 ], +"order_size": [ 2, 6 ], +"passages_size": [ 0, 10 ] +} \ No newline at end of file diff --git a/resources/4c01589b/4c01589b_code.scd b/resources/4c01589b/4c01589b_code.scd new file mode 100644 index 0000000..b11446a --- /dev/null +++ b/resources/4c01589b/4c01589b_code.scd @@ -0,0 +1,718 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck, +msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON; + +// model vars +//(model and global vars mostly set by OSC funcs +var curUID, refUID, orderSeed, durSeed, motifSeed, +entrancesProbVals, passagesProbVals, exitsProbVals, +ranges, orders, susWeights, passagesWeights, passagesSize, orderSize; + +// model aux vars +var entrancesDurFunc, passagesDurFunc, exitsDurFunc; + +// other global vars +var lastXChanges, popSize, exPath, dir, primes, dims, tuples, +seq, group, player, ledgerPath, ledger, currentlyPlayingUID; + + +// install JSON quark +if(Quarks.isInstalled("JSONlib").not, { + Quarks.install("https://github.com/musikinformatik/JSONlib.git"); + thisProcess.recompile; + //HelpBrowser.openHelpFor("Classes/JSONlib"); +}); + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genDurFunc = {arg chordProb, min, max, envData; + var env, pTable, durFunc; + env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + durFunc = {arg allowChord; + var res; + res = if(allowChord.not, { + pTable.tableRand * (max - min) + min + }, { + if(1.0.rand < chordProb, {0}, {pTable.tableRand * (max - min) + min}); + }).round(0.125); + if(res.asInteger == res, {res = res.asInteger}); + res + }; + seedFunc.value(durFunc, durSeed); +}; + +genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5; + ((maxMotifLength - minMotifLength).rand + minMotifLength).collect({ + var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order; + noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum); + noProgIns = (popSize - noSusIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] + }); +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = passagesWeights; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, flatOrder, res, isInChord, allowChord, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + flatOrder = silent ++ sus ++ prog; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + isInChord = popSize.collect({false}); + allowChord = false; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + flatOrder.do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + allowChord = if((sus ++ silent).includes(ins), { + (sus ++ silent).includes(ins) && (ins != sus.last); + }, { + if(i < (flatOrder.size - 1), {(isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not}, {false}); + }); + dur = passagesDurFunc.value(allowChord); + if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})}); + + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + + // pad ending + if(isLastOrder, { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + allowChord = (voices != popSize.collect({["Rest"]})); + dur = passagesDurFunc.value(allowChord); + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = { + var repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + + orders.do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~addr.sendMsg(~indexPath, ~indexMsg); + ~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3)); + //~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln); + }; +}); + +genPatterns = {arg inSeq, addr; + var voices, durs, patterns, res, indices, sectionDurs, ids, seq; + seq = inSeq.collect({arg mSeq; mSeq[0]}); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + indices = inSeq.collect({arg mSeq, m; mSeq[1]}); + ids = inSeq.collect({arg mSeq, m; mSeq[2]}); + sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum}); + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ) + }) ++ + [ + Pbind( + \type, \osc, + \addr, addr, + \indexPath, "/cur_play_index", + \indexMsg, Pseq(indices.postln, 1), + \seqPath, "/mus_seq", + \seqMsg, Pseq(seq, 1), + \dur, Pseq(sectionDurs, 1) + ); + ] + ); + res +}; + +/* +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; +*/ + + +//------resource management funcs + +genUID = {Date.seed.asHexString.toLower}; + +seedFunc = {arg func, seed; + var funcArgs, next; + next = Routine({loop{func.valueArray(funcArgs).yield }}); + next.randSeed_(seed); + {arg ...args; funcArgs = args; next.value} +}; + +stringifyToDepth = {arg data, maxDepth = 1; + var prettyString = "", rCount = 0, writeArray, indent; + + if(maxDepth == 0, { + data.asCompileString + }, { + indent = {arg size; size.collect({" "}).join("")}; + writeArray = {arg array; + prettyString = prettyString ++ indent.value(rCount) ++ "[\n"; + rCount = rCount + 1; + if(rCount < (maxDepth - 0), { + array.do({arg subArray; writeArray.value(subArray)}); + }, { + prettyString = prettyString ++ array.collect({arg subArray; + indent.value(rCount + 1) ++ subArray.asCompileString + }).join(",\n"); + }); + rCount = rCount - 1; + prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n"; + }; + + writeArray.value(data); + prettyString.replace(",\n\n", "\n").drop(-2); + }) +}; + +sanityCheck = {arg motif, index; + //print functions = very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true; + var res; + + res = in; + if(res.isNil.not, { + if((res.isArray && res.isString.not), { + res = res.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + if(escapeSingleQuotes, {res = res.replace("\'", "")}); + if(escapeDoubleQuotes, {res = res.replace("\"", "")}); + res = res.replace("Rest", "\"Rest\""); + res = res.interpret; + }, { + //res.postln; + if(res.every({arg char; char.isDecDigit}), {res = res.asInteger}); + }); + }); + res +}; + +writeResources = {arg path; + var file, nameSpaces, modelItems, resString; + file = File(path,"w"); + + nameSpaces = [ + "music_data", "last_changes", + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + modelItems = [ + seq, lastXChanges, + curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize + ]; + + resString = [nameSpaces, modelItems].flop.collect({arg item; + var nameSpace, modelItem, depth = 0, insert = " "; + # nameSpace, modelItem = item; + if(nameSpace == "music_data", {depth = 3; insert = "\n"}); + if(nameSpace == "last_changes", {depth = 1; insert = "\n"}); + if(nameSpace == "order", {depth = 1; insert = "\n"}); + "\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem.postln, depth).postln + }).join(",\n"); + + resString = "{\n" ++ resString ++ "\n}"; + + file.write(resString); + file.close; +}; + +loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)}; + +loadModelJSON = {arg model; + var nameSpaces, data; + + //model = File(path, "r").readAllString.parseJSON; + + nameSpaces = [ + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + data = nameSpaces.collect({arg nS; msgInterpret.value(model[nS]).postln}); + + data.postln; + + # curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize = data; + + popSize = ranges.size; +}; + +loadLedgerFile = {arg path; + ledgerPath = path; + loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON) +}; + +loadLedgerJSON = {arg ledger; ledger = ledger["ledger"]}; + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +//popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +//refUID = nil; +group = Group.new; +loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json"); +//passagesWeights = [1, 1, 1, 1, 1]; +//susWeights = [1, 1, 1]; + + +//------OSC funcs + +OSCdef(\load_ledger, {arg msg, time, addr, port; + loadLedgerFile.value(msg[1].asString); +}, \load_ledger); + +OSCdef(\load_model, {arg msg, time, addr, port; + loadModelFile.value(msg[1].asString); +}, \load_model); + + +OSCdef(\generate, {arg msg, time, addr, port; + var path, dFormat, condition, musPath; + msg.postln; + + path = msg[1].asString; + + loadModelFile.value(path); + + refUID.postln; + + loadLedgerFile.value(ledgerPath); + if(ledger.last != "tmp", {ledger = ledger.add("tmp")}); + + lastXChanges = if(refUID == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + refUID.postln; + file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..2] ++ [entrancesProbVals[3..]]); + passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..2] ++ [passagesProbVals[3..]]); + exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..2] ++ [exitsProbVals[3..]]); + + if(orders == nil, { + orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize); + addr.sendMsg("/order", stringifyToDepth.value(orders, 1)); + }); + seq = seedFunc.value(genMotif, motifSeed).value; + + //musPath = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath; + writeResources.value(path); + + //orders = nil; + //addr.sendMsg("/current_uid", curUID); + //addr.sendMsg("/ledger", prettifyArray.value(ledger, 1).replace("\"", "")); + //addr.sendMsg("/ledger_size", ledger.size); + //addr.sendMsg("/mus_seq", prettifyArray.value(seq, 3)); + addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3)); +}, \generate); + + +OSCdef(\commit, {arg msg, time, addr, port; + var newLedger, modelPath, musString, musFile, test1, test2; + msg.postln; + + /* + test1 = msg[1].asString.parseJSON; + test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile; + msgInterpret.value(test1["music"])[0][0][0][1].class.postln; + msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln; + (test1["music"] == test2["music_data"]).postln; + */ + + curUID = genUID.value; + File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath); + File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath); + + modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; + writeResources.value(modelPath); + + File.delete(ledgerPath.postln ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath.postln, "w"); + ledger = ledger.postln.drop(-1).add(curUID); + newLedger.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}"); + newLedger.close; + + addr.sendMsg("/committed", curUID, ledgerPath); + //refUID = curUID; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + // the cued sequence can now be read from file, so this can be cleaned up + var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; + pSeq = []; + cuedSeek = (seq != nil); + indexStart = msg[2].asInteger; + indexEnd = ledger.size - if(cuedSeek, {2}, {1}); + if(((indexStart == (ledger.size - 1)) && cuedSeek).not, { + ledger[indexStart..indexEnd].do({arg uid, index; + var file; + (indexStart + index).postln; + file = File((dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_music" ++ ".json").standardizePath, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), indexStart + index, uid]); + file.close; + }); + }); + if(cuedSeek, {pSeq = pSeq.add([seq, ledger.size - 1])}); + patterns = genPatterns.value(pSeq, addr); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; + +1223423434123.asHexString.toLower + +Date.getDate.rawSeconds +Date.seed.asHexString.toLower + +n = NetAddr("localhost", 8080); +n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals"); \ No newline at end of file diff --git a/resources/4c01589b/4c01589b_gui_state.json b/resources/4c01589b/4c01589b_gui_state.json new file mode 100644 index 0000000..2bc73d6 --- /dev/null +++ b/resources/4c01589b/4c01589b_gui_state.json @@ -0,0 +1,1359 @@ +{ + "motif_label": "motif", + "seeds_label": "seeds", + "order": "[\n [ [ 3, 1, 0 ], [ 2 ], [ ] ],\n [ [ 1, 2 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 3 ] ],\n [ [ 3, 2 ], [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], [ 0 ] ],\n [ [ 2, 3 ], [ 0, 1, 0 ], [ ] ]\n]", + "order_lock": 1, + "order_size": [ + 3, + 8 + ], + "order_size_v2": 8, + "order_size_v1": 3, + "order_size_panel": -1, + "passage_size_v2": 8, + "passage_size_v1": 2, + "passage_size_panel": -1, + "sus_weights": [ + null, + null, + null + ], + "range_matrix": [ + null, + null, + null, + null + ], + "instrumentation": [ + 0, + 0 + ], + "entrances_probs_sync": "passages", + "entrances": -1, + "passages_probs_sync": "passages", + "passages": -1, + "exits_probs_sync": "passages", + "exits": -1, + "dur_panel": 0, + "durations": -1, + "passages_weights": [ + null, + null, + null, + null, + null + ], + "weights": -1, + "seeds_tab_panel": 0, + "weights_seed_lock": 0, + "weights_seed": 534103, + "sus_weights/0_slider_val": 0.21, + "sus_weights/0_slider_slider": 0.21, + "sus_weights/0_slider_input": 0.21, + "sus_weights/0_slider_label": 1, + "sus_weights/0_slider": -1, + "sus_weights/1_slider_val": 0.35, + "sus_weights/1_slider_slider": 0.35, + "sus_weights/1_slider_input": 0.35, + "sus_weights/1_slider_label": 2, + "sus_weights/1_slider": -1, + "sus_weights/2_slider_val": 0.21, + "sus_weights/2_slider_slider": 0.21, + "sus_weights/2_slider_input": 0.21, + "sus_weights/2_slider_label": 3, + "sus_weights/2_slider": -1, + "passages_weights/0_slider_val": 0.49, + "passages_weights/0_slider_slider": 0.49, + "passages_weights/0_slider_input": 0.49, + "passages_weights/0_slider_label": "step", + "passages_weights/0_slider": -1, + "passages_weights/1_slider_val": 0.53, + "passages_weights/1_slider_slider": 0.53, + "passages_weights/1_slider_input": 0.53, + "passages_weights/1_slider_label": "dc", + "passages_weights/1_slider": -1, + "passages_weights/2_slider_val": 0.35, + "passages_weights/2_slider_slider": 0.35, + "passages_weights/2_slider_input": 0.35, + "passages_weights/2_slider_label": "range", + "passages_weights/2_slider": -1, + "passages_weights/3_slider_val": 0.59, + "passages_weights/3_slider_slider": 0.59, + "passages_weights/3_slider_input": 0.59, + "passages_weights/3_slider_label": "registration", + "passages_weights/3_slider": -1, + "passages_weights/4_slider_val": 0.39, + "passages_weights/4_slider_slider": 0.39, + "passages_weights/4_slider_input": 0.39, + "passages_weights/4_slider_label": "hd", + "passages_weights/4_slider": -1, + "range_matrix/0_val_input_min": -853.2067988668555, + "range_matrix/0_val_rslider": [ + -853.2067988668555, + 401 + ], + "range_matrix/0_val_input_max": 401, + "range_matrix/0_val": -1, + "range_matrix/1_val_input_min": -659, + "range_matrix/1_val_rslider": [ + -659, + 880 + ], + "range_matrix/1_val_input_max": 880, + "range_matrix/1_val": -1, + "range_matrix/2_val_input_min": -241, + "range_matrix/2_val_rslider": [ + -241, + 1869 + ], + "range_matrix/2_val_input_max": 1869, + "range_matrix/2_val": -1, + "range_matrix/3_val_input_min": -27, + "range_matrix/3_val_rslider": [ + -27, + 2063 + ], + "range_matrix/3_val_input_max": 2063, + "range_matrix/3_val": -1, + "entrances_probs_chord_slider_val": 0.66, + "entrances_probs_chord_slider_slider": 0.66, + "entrances_probs_chord_slider_input": 0.66, + "entrances_probs_chord_slider_label": "chord prob", + "entrances_probs_chord_slider": -1, + "entrances_probs_vals": [ + 0.63, + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.3963730569948187, + 0.8716216216216216, + 0.4948186528497409, + 0.5912162162162162, + 0.5362694300518135, + 0.8614864864864865, + 0.6424870466321243, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "entrances_probs": -1, + "passages_probs_chord_slider_val": 0.63, + "passages_probs_chord_slider_slider": 0.63, + "passages_probs_chord_slider_input": 0.63, + "passages_probs_chord_slider_label": "chord prob", + "passages_probs_chord_slider": -1, + "passages_probs_vals": [ + 0.63, + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.3963730569948187, + 0.8716216216216216, + 0.4948186528497409, + 0.5912162162162162, + 0.5362694300518135, + 0.8614864864864865, + 0.6424870466321243, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "passages_probs": -1, + "exits_probs_chord_slider_val": 0, + "exits_probs_chord_slider_slider": 0, + "exits_probs_chord_slider_input": 0, + "exits_probs_chord_slider_label": "chord prob", + "exits_probs_chord_slider": -1, + "exits_probs_vals": [ + 0, + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.4948186528497409, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "exits_probs": -1, + "step_env_env_vals": [ + 0, + 5, + 0, + 0, + 0, + 0, + 0.14609053497942387, + 0.7613636363636364, + 0.20164609053497942, + 0.26136363636363635, + 0.24279835390946503, + 0.7215909090909092, + 0.39094650205761317, + 0.875, + 0.4567901234567901, + 0.44318181818181823, + 0.5432098765432098, + 0.34659090909090906, + 0.6481481481481481, + 0.8011363636363636, + 0.6810699588477366, + 0.5170454545454546, + 0.8868312757201646, + 0.49431818181818177, + 0.8868312757201646, + 0.49431818181818177 + ], + "step_env_env_canvas": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0.14609053497942387, + 0.7613636363636364 + ], + [ + 0.20164609053497942, + 0.26136363636363635 + ], + [ + 0.24279835390946503, + 0.7215909090909092 + ], + [ + 0.39094650205761317, + 0.875 + ], + [ + 0.4567901234567901, + 0.44318181818181823 + ], + [ + 0.5432098765432098, + 0.34659090909090906 + ], + [ + 0.6481481481481481, + 0.8011363636363636 + ], + [ + 0.6810699588477366, + 0.5170454545454546 + ], + [ + 0.8868312757201646, + 0.49431818181818177 + ], + [ + 0.8868312757201646, + 0.49431818181818177 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "step_env_env_size": 12, + "step_env_env_flatten": 0, + "step_env_env_rslider": [ + 0, + 5 + ], + "step_env_env_rslider_v2": 5, + "step_env_env_rslider_v1": 0, + "step_env_env_mpos": "", + "step_env_env": -1, + "entrances_probs_dur_env_vals": [ + 0.515267175572519, + 4.599236641221374, + 0, + 0.5, + 0.2772020725388601, + 0.7972972972972973, + 0.45077720207253885, + 0.8783783783783784, + 0.5, + 0.5, + 0.727979274611399, + 0.45270270270270274, + 0.7357512953367875, + 0.6486486486486487, + 0.8911917098445595, + 0.7905405405405406, + 1, + 0.5 + ], + "entrances_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.2772020725388601, + 0.7972972972972973 + ], + [ + 0.45077720207253885, + 0.8783783783783784 + ], + [ + 0.5, + 0.5 + ], + [ + 0.727979274611399, + 0.45270270270270274 + ], + [ + 0.7357512953367875, + 0.6486486486486487 + ], + [ + 0.8911917098445595, + 0.7905405405405406 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "entrances_probs_dur_env_size": 8, + "entrances_probs_dur_env_flatten": 0, + "entrances_probs_dur_env_rslider": [ + 0.515267175572519, + 4.599236641221374 + ], + "entrances_probs_dur_env_rslider_v2": 4.599236641221374, + "entrances_probs_dur_env_rslider_v1": 0.515267175572519, + "entrances_probs_dur_env_mpos": "", + "entrances_probs_dur_env": -1, + "passages_probs_dur_env_vals": [ + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.3963730569948187, + 0.8716216216216216, + 0.4948186528497409, + 0.5912162162162162, + 0.5362694300518135, + 0.8614864864864865, + 0.6424870466321243, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "passages_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.23316062176165803, + 0.7094594594594594 + ], + [ + 0.3963730569948187, + 0.8716216216216216 + ], + [ + 0.4948186528497409, + 0.5912162162162162 + ], + [ + 0.5362694300518135, + 0.8614864864864865 + ], + [ + 0.6424870466321243, + 0.5912162162162162 + ], + [ + 0.7901554404145078, + 0.8277027027027027 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "passages_probs_dur_env_size": 8, + "passages_probs_dur_env_flatten": 0, + "passages_probs_dur_env_rslider": [ + 0, + 5 + ], + "passages_probs_dur_env_rslider_v2": 5, + "passages_probs_dur_env_rslider_v1": 0, + "passages_probs_dur_env_mpos": "", + "passages_probs_dur_env": -1, + "exits_probs_dur_env_vals": [ + 0, + 5, + 0, + 0.5, + 0.5, + 0.5, + 1, + 0.5 + ], + "exits_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.5, + 0.5 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "exits_probs_dur_env_size": 3, + "exits_probs_dur_env_flatten": 0, + "exits_probs_dur_env_rslider": [ + 0, + 5 + ], + "exits_probs_dur_env_rslider_v2": 5, + "exits_probs_dur_env_rslider_v1": 0, + "exits_probs_dur_env_mpos": "", + "exits_probs_dur_env": -1, + "mus_seq": [ + [ + [ + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + "Rest" + ], + [ + "Rest" + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + "Rest" + ] + ], + 1.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + 0, + 1, + -3, + 0, + 2, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.75 + ], + [ + [ + [ + 1, + 1, + -2, + -2, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.625 + ], + [ + [ + [ + 1, + 1, + -3, + -1, + 0, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.625 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ] + ], + [ + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -2, + 0, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.375 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 2, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -2, + -1, + 2, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 0, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.875 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1 + ] + ], + [ + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 2, + 0, + -3, + -1, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.625 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + "Rest" + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + "Rest" + ] + ], + 1.875 + ], + [ + [ + [ + "Rest" + ], + [ + "Rest" + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + "Rest" + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + "Rest" + ], + [ + "Rest" + ], + [ + "Rest" + ] + ], + 0.875 + ] + ] + ] + ], + "root": [ + 0.20743639921722112, + 0 + ], + "order_seed": 798574, + "dur_seed": 884869, + "passages_size": [ + 0, + 10 + ], + "dur_seed_lock": 1, + "order_seed_lock": 0, + "seeds_panel": -1, + "motif_panel": [ + 0, + 0 + ], + "ref_uid": "6f1a789f", + "cur_uid": "4c01589b" +} \ No newline at end of file diff --git a/resources/4c01589b/4c01589b_mus_model.json b/resources/4c01589b/4c01589b_mus_model.json new file mode 100644 index 0000000..436b630 --- /dev/null +++ b/resources/4c01589b/4c01589b_mus_model.json @@ -0,0 +1,85 @@ +{ +"music_data": +[ + [ + [ + [ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 1.75 ], + [ [ [ "Rest" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0 ], + [ [ [ "Rest" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ] ], 0 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ] ], 1.25 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ] ], 1.75 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ] ], 0 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ] ], 0 ], + [ [ [ -1, 0, 0, 1, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ] ], 0.875 ], + [ [ [ 1, 0, 0, -1, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ] ], 0 ], + [ [ [ 1, 0, 0, -1, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ] ], 1.625 ], + [ [ [ 1, -1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ] ], 1.75 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ] ], 0 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 0.875 ] + ], + [ + [ [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ -1, 1, 1, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 0.625 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, -1 ], [ 1, 0, 0, -1, 0, 0 ] ], 1.625 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 1, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 1.125 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 1, 0, -1, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 1 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 0.5 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 1 ], [ 1, 0, 0, -1, 0, 0 ] ], 1.625 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 1.5 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, -1 ], [ 1, 0, 0, -1, 0, 0 ] ], 0.5 ] + ], + [ + [ [ [ 0, 1, 0, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 0 ], [ 0, 1, 0, 0, 0, -1 ], [ 1, 0, 0, -1, 0, 0 ] ], 0.5 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ 0, 1, 0, -1, 0, 0 ], [ 0, 1, 0, 0, 0, -1 ], [ 1, 0, 0, -1, 0, 0 ] ], 1.5 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 1, 0, -1 ], [ 0, 1, 0, 0, 0, -1 ], [ 1, 0, 0, -1, 0, 0 ] ], 1.5 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, -1, 0 ], [ 0, 1, 0, 0, 0, -1 ], [ 1, 0, 0, -1, 0, 0 ] ], 1.125 ] + ], + [ + [ [ [ 0, 1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, -1, 0 ], [ 0, 1, 0, 0, 0, -1 ], [ "Rest" ] ], 0 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 1, 0, 0, 0, -1 ], [ "Rest" ] ], 0 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 1.375 ] + ], + [ + [ [ [ 0, 1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 1.75 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 1, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 1.875 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 0.75 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ 0, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 1.25 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 1 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 1.375 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 2 ], + [ [ [ "Rest" ], [ 1, 0, 0, -1, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 0 ], + [ [ [ "Rest" ], [ 1, 0, 0, -1, -1, 0 ], [ "Rest" ], [ 1, 0, 0, -1, 0, 0 ] ], 1.75 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ 1, 0, 0, -1, 0, 0 ] ], 0 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 1 ] + ] + ] +], +"last_changes": +[ + [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], + [ [ 0, 1, 0, 0, 0, 0 ], [ 0, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], + [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], + [ [ 0, 1, 0, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], + [ [ 0, 1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ] +], +"cur_uid": "4c01589b", +"ref_uid": "nil", +"order_seed": 720097, +"dur_seed": 979064, +"motifs_seed": 718021, +"entrances_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ], +"passages_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"exits_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ], +"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ], +"order": +[ + [ [ 2 ], [ 1, 3, 0, 1, 1, 3, 0, 0, 3, 0, 0, 3 ], [ ] ], + [ [ 1, 0, 3 ], [ 2, 2, 2, 2, 2, 2, 2, 2 ], [ ] ], + [ [ 3, 2, 0 ], [ 1, 1, 1, 1 ], [ ] ], + [ [ 0 ], [ 2 ], [ 3, 1 ] ], + [ [ 0, 2, 3 ], [ 1, 1, 1, 1, 1, 1 ], [ ] ] +], +"sus_weights": [ 0.75, 0.69, 0.75 ], +"order_size": [ 2, 6 ], +"passages_size": [ 0, 10 ] +} \ No newline at end of file diff --git a/resources/55930f4d/55930f4d_code.scd b/resources/55930f4d/55930f4d_code.scd new file mode 100644 index 0000000..caa982a --- /dev/null +++ b/resources/55930f4d/55930f4d_code.scd @@ -0,0 +1,757 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck, +msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON; + +// model vars +//(model and global vars mostly set by OSC funcs +var seq, lastXChanges, +curUID, refUID, orderSeed, durSeed, motifSeed, +entrancesProbVals, passagesProbVals, exitsProbVals, +ranges, passagesWeights, orders, susWeights, orderSize, passagesSize, +motifEdited, orderEdited; + +// model aux vars +var entrancesDurFunc, passagesDurFunc, exitsDurFunc; + +// other global vars +var popSize, exPath, dir, primes, dims, tuples, +group, player, ledgerPath, ledger, currentlyPlayingUID; + + +// install JSON quark +if(Quarks.isInstalled("JSONlib").not, { + Quarks.install("https://github.com/musikinformatik/JSONlib.git"); + thisProcess.recompile; + //HelpBrowser.openHelpFor("Classes/JSONlib"); +}); + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genDurFunc = {arg chordProb, minPad, maxPad, minDur, maxDur, envData, seed; + var env, pTable, durFunc; + env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + [chordProb, minPad, maxPad, minDur, maxDur, envData].postln; + durFunc = {arg allowChord, pad = false; + var res; + res = if(allowChord.not, { + pTable.tableRand * (maxDur - minDur) + minDur + }, { + if(1.0.rand < chordProb, {0}, {pTable.tableRand * (maxDur - minDur) + minDur}); + }).round(0.125); + if(pad, {res = res + rrand(minPad.asFloat, maxPad.asFloat).round(0.125)}); + if(res.asInteger == res, {res = res.asInteger}); + res + }; + seedFunc.value(durFunc, seed); +}; + +genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5; + ((maxMotifLength - minMotifLength).rand + minMotifLength).collect({ + var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order; + noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum); + noProgIns = (popSize - noSusIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] + }); +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = passagesWeights; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, flatOrder, res, isInChord, allowChord, pad, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + flatOrder = silent ++ sus ++ prog; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + isInChord = popSize.collect({false}); + allowChord = false; + pad = false; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + flatOrder.do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + + if((sus ++ silent).includes(ins), { + allowChord = (ins != sus.last); + pad = (ins == sus.last); + }, { + if(i < (flatOrder.size - 1), { + allowChord = (isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not; + pad = false; + }, { + allowChord = false; + pad = true + }); + }); + if((orderIndex == 0) && sus.includes(ins), { + dur = entrancesDurFunc.value(allowChord, pad); + }, { + dur = passagesDurFunc.value(allowChord, pad); + }); + if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})}); + + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + + // pad ending + if(orderIndex == (orders.size - 1), { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + allowChord = (voices != popSize.collect({["Rest"]})); + pad = allowChord.not; + dur = exitsDurFunc.value(allowChord, pad); + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = { + var repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + + orders.do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +/* +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~addr.sendMsg(~indexPath, ~indexMsg); + ~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3)); + //~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln); + }; +}); +*/ + +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~msg.postln; + ~addr.sendMsg(~path, *~msg); + }; +}); + +genPatterns = {arg inSeq, addr; + var voices, durs, patterns, res, indices, sectionDurs, msg, ids, seq; + seq = inSeq.collect({arg mSeq; mSeq[0]}); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + msg = inSeq.collect({arg mSeq, m; mSeq[1..]}); + //ids = inSeq.collect({arg mSeq, m; mSeq[2]}); + sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum}); + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ) + }) ++ + [ + Pbind( + \type, \osc, + \addr, addr, + //\indexPath, "/cur_play_index", + //\indexMsg, Pseq(indices, 1), + //\seqPath, "/mus_seq", + //\seqMsg, Pseq(seq, 1), + \path, "/playing", + \msg, Pseq(msg, 1), + \dur, Pseq(sectionDurs, 1) + ); + ] + ); + res +}; + +/* +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; +*/ + + +//------resource management funcs + +genUID = {Date.seed.asHexString.toLower}; + +seedFunc = {arg func, seed; + var funcArgs, next; + next = Routine({loop{func.valueArray(funcArgs).yield }}); + next.randSeed_(seed); + {arg ...args; funcArgs = args; next.value} +}; + +stringifyToDepth = {arg data, maxDepth = 1; + var prettyString = "", rCount = 0, writeArray, indent; + + if(maxDepth == 0, { + data.asCompileString + }, { + indent = {arg size; size.collect({" "}).join("")}; + writeArray = {arg array; + prettyString = prettyString ++ indent.value(rCount) ++ "[\n"; + rCount = rCount + 1; + if(rCount < maxDepth, { + array.do({arg subArray; writeArray.value(subArray)}); + }, { + prettyString = prettyString ++ array.collect({arg subArray; + indent.value(rCount + 1) ++ subArray.asCompileString + }).join(",\n"); + }); + rCount = rCount - 1; + prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n"; + }; + + writeArray.value(data); + prettyString.replace(",\n\n", "\n").drop(-2); + }) +}; + +sanityCheck = {arg motif, index; + //print functions = very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true; + var res; + + res = in; + if(res.isNil.not, { + if((res.isArray && res.isString.not), { + res = res.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + if(escapeSingleQuotes, {res = res.replace("\'", "")}); + if(escapeDoubleQuotes, {res = res.replace("\"", "")}); + res = res.replace("Rest", "\"Rest\""); + res = res.interpret; + }, { + //res.postln; + if(res.every({arg char; char.isDecDigit}), {res = res.asInteger}); + }); + }); + res +}; + +writeResources = {arg path; + var file, nameSpaces, modelItems, resString; + file = File(path,"w"); + + nameSpaces = [ + "music_data", "last_changes", + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size", + "motif_edited", "order_edited" + ]; + + modelItems = [ + seq, lastXChanges, + curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize, + motifEdited, orderEdited + ]; + + resString = [nameSpaces, modelItems].flop.collect({arg item; + var nameSpace, modelItem, depth = 0, insert = " "; + # nameSpace, modelItem = item; + if(nameSpace == "music_data", {depth = 3; insert = "\n"}); + if(nameSpace == "last_changes", {depth = 1; insert = "\n"}); + if(nameSpace == "order", {depth = 1; insert = "\n"}); + if((nameSpace == "ref_uid") && (modelItem == nil), {modelItem = "nil"}); + "\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem, depth) + }).join(",\n"); + + resString = "{\n" ++ resString ++ "\n}"; + + file.write(resString); + file.close; + resString +}; + +loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)}; + +loadModelJSON = {arg jsonObject; + var nameSpaces, data; + + //model = File(path, "r").readAllString.parseJSON; + + nameSpaces = [ + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size", + "motif_edited", "order_edited" + ]; + + data = nameSpaces.collect({arg nS; msgInterpret.value(jsonObject[nS])}); + + //data.postln; + + # curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize, + motifEdited, orderEdited = data; + + popSize = ranges.size; +}; + +loadLedgerFile = {arg path; + ledgerPath = path; + loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON) +}; + +loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]}; + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +//popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +//refUID = nil; +group = Group.new; +loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json"); +//passagesWeights = [1, 1, 1, 1, 1]; +//susWeights = [1, 1, 1]; + + +//------OSC funcs + +OSCdef(\load_ledger, {arg msg, time, addr, port; + loadLedgerFile.value(msg[1].asString); +}, \load_ledger); + +OSCdef(\load_model, {arg msg, time, addr, port; + loadModelFile.value(msg[1].asString); +}, \load_model); + + +OSCdef(\generate, {arg msg, time, addr, port; + var path, durSeeds, musPath, modelString; + msg.postln; + + path = msg[1].asString; + + loadModelFile.value(path); + + //refUID.postln; + + loadLedgerFile.value(ledgerPath); + if(ledger == nil, {ledger = ["tmp"]}); + if(ledger.last != "tmp", {ledger = ledger.add("tmp")}); + + lastXChanges = if(refUID == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln; + entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..4] ++ [entrancesProbVals[5..]] ++ [durSeeds[0]]); + passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..4] ++ [passagesProbVals[5..]] ++ [durSeeds[1]]); + exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..4] ++ [exitsProbVals[5..]] ++ [durSeeds[2]]); + + if(orders == nil, { + orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize); + //addr.sendMsg("/order", stringifyToDepth.value(orders, 1)); + }); + seq = seedFunc.value(genMotif, motifSeed).value; + + modelString = writeResources.value(path); + + //addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3)); + addr.sendMsg("/generated", path, modelString); +}, \generate); + + +OSCdef(\commit, {arg msg, time, addr, port; + var newLedger, modelPath, musString, musFile, test1, test2; + msg.postln; + + /* + test1 = msg[1].asString.parseJSON; + test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile; + msgInterpret.value(test1["music"])[0][0][0][1].class.postln; + msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln; + (test1["music"] == test2["music_data"]).postln; + */ + + curUID = genUID.value; + File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath); + File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath); + + modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; + writeResources.value(modelPath); + + File.delete(ledgerPath ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath, "w"); + ledger = ledger.drop(-1).add(curUID); + newLedger.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}"); + newLedger.close; + + addr.sendMsg("/committed", curUID, ledgerPath); + //refUID = curUID; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + // the cued sequence can now be read from file, so this can be cleaned up + var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; + pSeq = []; + cuedSeek = (seq != nil); + indexStart = msg[2].asInteger; + indexEnd = ledger.size - if(cuedSeek, {2}, {1}); + //ledger.postln; + if(((indexStart == (ledger.size - 1)) && cuedSeek).not, { + ledger[indexStart..indexEnd].do({arg uid, index; + var path, file; + path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath; + file = File(path, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, indexStart + index, uid]); + file.close; + }); + }); + if(cuedSeek, { + var path, file; + path = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath; + file = File(path, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]); + file.close; + }); + patterns = genPatterns.value(pSeq, addr); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); + //Out.ar([0, 1], sig1 * EnvGen.kr(Env.asr(dur, 0.3, 1), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; + +1223423434123.asHexString.toLower + +Date.getDate.rawSeconds +Date.seed.asHexString.toLower + +n = NetAddr("localhost", 8080); +n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals"); \ No newline at end of file diff --git a/resources/55930f4d/55930f4d_mus_model.json b/resources/55930f4d/55930f4d_mus_model.json new file mode 100644 index 0000000..4fb909f --- /dev/null +++ b/resources/55930f4d/55930f4d_mus_model.json @@ -0,0 +1,105 @@ +{ +"music_data": +[ + [ + [ + [ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 3.75 ], + [ [ [ "Rest" ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 1.125 ], + [ [ [ "Rest" ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ] ], 1.375 ], + [ [ [ "Rest" ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ] ], 1.75 ], + [ [ [ "Rest" ], [ 0, 0, 1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ] ], 0.875 ], + [ [ [ "Rest" ], [ 0, 0, 1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ -1, 0, 0, 0, 0, 1 ] ], 1 ], + [ [ [ "Rest" ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ -1, 0, 0, 0, 0, 1 ] ], 0 ], + [ [ [ "Rest" ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, -1, 0, 0, 0 ] ], 1.75 ], + [ [ [ "Rest" ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], 1.625 ], + [ [ [ "Rest" ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 2 ], + [ [ [ "Rest" ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 0.875 ], + [ [ [ "Rest" ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 5 ] + ], + [ + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 1.375 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, -1, 0, 1 ], [ 0, 0, 0, -1, 0, 0 ] ], 0.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, -1, 1, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 1.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 1.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 1, -1, 0, -1, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 1.25 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 1, -1, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 0.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, -1, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 1 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 1, 0, 0, -1, -1, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 1 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, -1 ], [ 0, 0, 0, -1, 0, 0 ] ], 2 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 3.625 ] + ], + [ + [ [ [ 0, 0, 0, -1, 0, 1 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 0 ], + [ [ [ 0, 0, 0, -1, 0, 1 ], [ 0, -1, 0, 0, 0, 1 ], [ 0, -1, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 1 ], + [ [ [ 1, -1, 0, -1, 0, 0 ], [ 0, -1, 0, 0, 0, 1 ], [ 0, -1, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 0.875 ], + [ [ [ 1, -1, 0, -1, 0, 0 ], [ 1, 0, -1, -1, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 1.75 ], + [ [ [ 1, -1, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 1.5 ], + [ [ [ 1, -1, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 0 ], + [ [ [ 1, -1, 0, 0, 0, -1 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, -1, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 1.25 ], + [ [ [ 0, 1, 0, -1, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, -1, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 5.25 ] + ], + [ + [ [ [ 0, -1, 0, 1, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, -1, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 0 ] ], 1.125 ], + [ [ [ 0, -1, 0, 1, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, -1, 0, 0, 0, 0 ], [ 1, -1, 0, -1, -1, 0 ] ], 1.125 ], + [ [ [ 0, -1, 0, 1, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, -1, 1, 0, -1, 0 ], [ 1, -1, 0, -1, -1, 0 ] ], 1.875 ], + [ [ [ 0, -1, 0, 1, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 1, -2, 0, 0, -1, 0 ], [ 1, -1, 0, -1, -1, 0 ] ], 1.25 ], + [ [ [ 0, -1, 0, 1, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 1, -2, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, -1 ] ], 1.625 ], + [ [ [ 0, -1, 0, 1, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, -1 ] ], 0 ], + [ [ [ 0, -1, 0, 1, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 0, -1, 1, 0, -1, 0 ] ], 1.5 ], + [ [ [ 0, -1, 0, 0, -1, 1 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 0, -1, 1, 0, -1, 0 ] ], 0.625 ], + [ [ [ 0, -1, 0, 0, -1, 1 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -2, 0, 0, -1, 0 ] ], 1.625 ], + [ [ [ 1, -1, -1, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -2, 0, 0, -1, 0 ] ], 1.625 ], + [ [ [ 1, -1, -1, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ] ], 1.875 ], + [ [ [ 1, -1, -1, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], 5.125 ] + ], + [ + [ [ [ 1, -1, -1, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], 0.75 ], + [ [ [ 1, -1, -1, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ], [ 0, 0, 0, 0, -1, 0 ] ], 0 ], + [ [ [ 0, -1, 0, 1, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ], [ 0, 0, 0, 0, -1, 0 ] ], 0.625 ], + [ [ [ 0, -1, 0, 0, -1, 1 ], [ 1, -1, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ], [ 0, 0, 0, 0, -1, 0 ] ], 1.375 ], + [ [ [ 0, -1, 0, 0, -1, 1 ], [ 1, -1, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ], [ 1, -1, -1, 0, -1, 0 ] ], 4.875 ] + ], + [ + [ [ [ 0, -1, 0, 0, -1, 1 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 1, -1, -1, 0, -1, 0 ] ], 0.875 ], + [ [ [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 1, -1, -1, 0, -1, 0 ] ], 1.75 ], + [ [ [ 0, -1, -1, 0, -1, 1 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 1, -1, -1, 0, -1, 0 ] ], 1.375 ], + [ [ [ 0, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 1, -1, -1, 0, -1, 0 ] ], 4.375 ], + [ [ [ "Rest" ], [ 1, -1, 0, 0, -1, 0 ], [ "Rest" ], [ 1, -1, -1, 0, -1, 0 ] ], 0 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ 1, -1, -1, 0, -1, 0 ] ], 1.875 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 5 ] + ] + ] +], +"last_changes": +[ + [ [ 0, -1, 0, 0, -1, 1 ], [ 1, -1, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ], [ 0, 0, 0, 0, -1, 0 ] ], + [ [ 0, -1, 0, 0, -1, 1 ], [ 1, -1, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ], [ 1, -1, -1, 0, -1, 0 ] ], + [ [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ], [ 1, -1, -1, 0, -1, 0 ] ], + [ [ 0, -1, -1, 0, -1, 1 ], [ 1, -1, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ], [ 1, -1, -1, 0, -1, 0 ] ], + [ [ 0, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ], [ 1, -1, -1, 0, -1, 0 ] ] +], +"cur_uid": "55930f4d", +"ref_uid": "nil", +"order_seed": 751178, +"dur_seed": 630355, +"motifs_seed": 318398, +"entrances_probs_vals": [ 0.33687943262411, 1.91, 4.44, 0.5, 2, 0, 0.5, 0.24509803921569, 0.89189189189189, 0.5, 1, 0.5, 0.5, 0.8562091503268, 0.69932432432432, 1, 0.5 ], +"passages_probs_vals": [ 0.33687943262411, 1.91, 4.44, 0.5, 2, 0, 0.5, 0.24509803921569, 0.89189189189189, 0.5, 1, 0.5, 0.5, 0.8562091503268, 0.69932432432432, 1, 0.5 ], +"exits_probs_vals": [ 0.33687943262411, 1.91, 4.44, 0.5, 2, 0, 0.5, 0.24509803921569, 0.89189189189189, 0.5, 1, 0.5, 0.5, 0.8562091503268, 0.69932432432432, 1, 0.5 ], +"ranges": [ [ -1200, 2400 ], [ -1200, 2400 ], [ -1200, 2400 ], [ -1200, 2400 ] ], +"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ], +"order": +[ + [ [ 2 ], [ 1, 3, 3, 1, 3, 1, 3, 3, 3, 1, 1 ], [ 0 ] ], + [ [ 0, 1, 3 ], [ 2, 2, 2, 2, 2, 2, 2, 2, 2 ], [ ] ], + [ [ 3, 2 ], [ 0, 1, 0, 1, 1, 0, 1, 0 ], [ ] ], + [ [ 1 ], [ 0, 3, 2, 2, 3, 2, 3, 0, 3, 0, 3, 3 ], [ ] ], + [ [ 1 ], [ 2, 3, 0, 0, 3 ], [ ] ], + [ [ 1, 3 ], [ 0, 0, 0 ], [ 2 ] ] +], +"sus_weights": [ 0.75, 0.75, 0.75 ], +"order_size": [ 1, 10 ], +"passages_size": [ 0, 10 ], +"motif_edited": "false", +"order_edited": "false" +} \ No newline at end of file diff --git a/resources/5cf1e9ab/5cf1e9ab_code.scd b/resources/5cf1e9ab/5cf1e9ab_code.scd new file mode 100644 index 0000000..0af80d7 --- /dev/null +++ b/resources/5cf1e9ab/5cf1e9ab_code.scd @@ -0,0 +1,723 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck, +msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON; + +// model vars +//(model and global vars mostly set by OSC funcs +var curUID, refUID, orderSeed, durSeed, motifSeed, +entrancesProbVals, passagesProbVals, exitsProbVals, +ranges, orders, susWeights, passagesWeights, passagesSize, orderSize; + +// model aux vars +var entrancesDurFunc, passagesDurFunc, exitsDurFunc; + +// other global vars +var lastXChanges, popSize, exPath, dir, primes, dims, tuples, +seq, group, player, ledgerPath, ledger, currentlyPlayingUID; + + +// install JSON quark +if(Quarks.isInstalled("JSONlib").not, { + Quarks.install("https://github.com/musikinformatik/JSONlib.git"); + thisProcess.recompile; + //HelpBrowser.openHelpFor("Classes/JSONlib"); +}); + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genDurFunc = {arg chordProb, min, max, envData; + var env, pTable, durFunc; + env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + durFunc = {arg allowChord; + var res; + res = if(allowChord.not, { + pTable.tableRand * (max - min) + min + }, { + if(1.0.rand < chordProb, {0}, {pTable.tableRand * (max - min) + min}); + }).round(0.125); + if(res.asInteger == res, {res = res.asInteger}); + res + }; + seedFunc.value(durFunc, durSeed); +}; + +genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5; + ((maxMotifLength - minMotifLength).rand + minMotifLength).collect({ + var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order; + noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum); + noProgIns = (popSize - noSusIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] + }); +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = passagesWeights; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, flatOrder, res, isInChord, allowChord, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + flatOrder = silent ++ sus ++ prog; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + isInChord = popSize.collect({false}); + allowChord = false; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + flatOrder.do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + + allowChord = if((sus ++ silent).includes(ins), { + //(sus ++ silent).includes(ins) && (ins != sus.last); + ins != sus.last; + }, { + i.postln; + flatOrder.postln; + if(i < (flatOrder.size - 1), {(isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not}, {false}); + }); + if((orderIndex == 0) && sus.includes(ins), { + dur = entrancesDurFunc.value(allowChord); + }, { + dur = passagesDurFunc.value(allowChord); + }); + //dur = passagesDurFunc.value(allowChord); + if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})}); + + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + + // pad ending + if(orderIndex == (orders.size - 1), { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + allowChord = (voices != popSize.collect({["Rest"]})); + dur = exitsDurFunc.value(allowChord); + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = { + var repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + + orders.do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~addr.sendMsg(~indexPath, ~indexMsg); + ~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3)); + //~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln); + }; +}); + +genPatterns = {arg inSeq, addr; + var voices, durs, patterns, res, indices, sectionDurs, ids, seq; + seq = inSeq.collect({arg mSeq; mSeq[0]}); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + indices = inSeq.collect({arg mSeq, m; mSeq[1]}); + ids = inSeq.collect({arg mSeq, m; mSeq[2]}); + sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum}); + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ) + }) ++ + [ + Pbind( + \type, \osc, + \addr, addr, + \indexPath, "/cur_play_index", + \indexMsg, Pseq(indices, 1), + \seqPath, "/mus_seq", + \seqMsg, Pseq(seq, 1), + \dur, Pseq(sectionDurs, 1) + ); + ] + ); + res +}; + +/* +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; +*/ + + +//------resource management funcs + +genUID = {Date.seed.asHexString.toLower}; + +seedFunc = {arg func, seed; + var funcArgs, next; + next = Routine({loop{func.valueArray(funcArgs).yield }}); + next.randSeed_(seed); + {arg ...args; funcArgs = args; next.value} +}; + +stringifyToDepth = {arg data, maxDepth = 1; + var prettyString = "", rCount = 0, writeArray, indent; + + if(maxDepth == 0, { + data.asCompileString + }, { + indent = {arg size; size.collect({" "}).join("")}; + writeArray = {arg array; + prettyString = prettyString ++ indent.value(rCount) ++ "[\n"; + rCount = rCount + 1; + if(rCount < maxDepth, { + array.do({arg subArray; writeArray.value(subArray)}); + }, { + prettyString = prettyString ++ array.collect({arg subArray; + indent.value(rCount + 1) ++ subArray.asCompileString + }).join(",\n"); + }); + rCount = rCount - 1; + prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n"; + }; + + writeArray.value(data); + prettyString.replace(",\n\n", "\n").drop(-2); + }) +}; + +sanityCheck = {arg motif, index; + //print functions = very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true; + var res; + + res = in; + if(res.isNil.not, { + if((res.isArray && res.isString.not), { + res = res.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + if(escapeSingleQuotes, {res = res.replace("\'", "")}); + if(escapeDoubleQuotes, {res = res.replace("\"", "")}); + res = res.replace("Rest", "\"Rest\""); + res = res.interpret; + }, { + //res.postln; + if(res.every({arg char; char.isDecDigit}), {res = res.asInteger}); + }); + }); + res +}; + +writeResources = {arg path; + var file, nameSpaces, modelItems, resString; + file = File(path,"w"); + + nameSpaces = [ + "music_data", "last_changes", + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + modelItems = [ + seq, lastXChanges, + curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize + ]; + + resString = [nameSpaces, modelItems].flop.collect({arg item; + var nameSpace, modelItem, depth = 0, insert = " "; + # nameSpace, modelItem = item; + if(nameSpace == "music_data", {depth = 3; insert = "\n"}); + if(nameSpace == "last_changes", {depth = 1; insert = "\n"}); + if(nameSpace == "order", {depth = 1; insert = "\n"}); + "\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem, depth) + }).join(",\n"); + + resString = "{\n" ++ resString ++ "\n}"; + + file.write(resString); + file.close; + resString +}; + +loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)}; + +loadModelJSON = {arg jsonObject; + var nameSpaces, data; + + //model = File(path, "r").readAllString.parseJSON; + + nameSpaces = [ + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + data = nameSpaces.collect({arg nS; msgInterpret.value(jsonObject[nS])}); + + //data.postln; + + # curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize = data; + + popSize = ranges.size; +}; + +loadLedgerFile = {arg path; + ledgerPath = path; + loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON) +}; + +loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]}; + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +//popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +//refUID = nil; +group = Group.new; +loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json"); +//passagesWeights = [1, 1, 1, 1, 1]; +//susWeights = [1, 1, 1]; + + +//------OSC funcs + +OSCdef(\load_ledger, {arg msg, time, addr, port; + loadLedgerFile.value(msg[1].asString); +}, \load_ledger); + +OSCdef(\load_model, {arg msg, time, addr, port; + loadModelFile.value(msg[1].asString); +}, \load_model); + + +OSCdef(\generate, {arg msg, time, addr, port; + var path, dFormat, condition, musPath, modelString; + msg.postln; + + path = msg[1].asString; + + loadModelFile.value(path); + + //refUID.postln; + + loadLedgerFile.value(ledgerPath); + if(ledger == nil, {ledger = ["tmp"]}); + if(ledger.last != "tmp", {ledger = ledger.add("tmp")}); + + lastXChanges = if(refUID == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..2] ++ [entrancesProbVals[3..]]); + passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..2] ++ [passagesProbVals[3..]]); + exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..2] ++ [exitsProbVals[3..]]); + + if(orders == nil, { + orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize); + //addr.sendMsg("/order", stringifyToDepth.value(orders, 1)); + }); + seq = seedFunc.value(genMotif, motifSeed).value; + + modelString = writeResources.value(path); + + //addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3)); + addr.sendMsg("/generated", path, modelString); +}, \generate); + + +OSCdef(\commit, {arg msg, time, addr, port; + var newLedger, modelPath, musString, musFile, test1, test2; + msg.postln; + + /* + test1 = msg[1].asString.parseJSON; + test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile; + msgInterpret.value(test1["music"])[0][0][0][1].class.postln; + msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln; + (test1["music"] == test2["music_data"]).postln; + */ + + curUID = genUID.value; + File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath); + File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath); + + modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; + writeResources.value(modelPath); + + File.delete(ledgerPath ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath, "w"); + ledger = ledger.drop(-1).add(curUID); + newLedger.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}"); + newLedger.close; + + addr.sendMsg("/committed", curUID, ledgerPath); + //refUID = curUID; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + // the cued sequence can now be read from file, so this can be cleaned up + var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; + pSeq = []; + cuedSeek = (seq != nil); + indexStart = msg[2].asInteger; + indexEnd = ledger.size - if(cuedSeek, {2}, {1}); + //ledger.postln; + if(((indexStart == (ledger.size - 1)) && cuedSeek).not, { + ledger[indexStart..indexEnd].do({arg uid, index; + var file; + file = File((dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), indexStart + index, uid]); + file.close; + }); + }); + if(cuedSeek, {pSeq = pSeq.add([seq, ledger.size - 1])}); + patterns = genPatterns.value(pSeq, addr); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; + +1223423434123.asHexString.toLower + +Date.getDate.rawSeconds +Date.seed.asHexString.toLower + +n = NetAddr("localhost", 8080); +n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals"); \ No newline at end of file diff --git a/resources/5cf1e9ab/5cf1e9ab_mus_model.json b/resources/5cf1e9ab/5cf1e9ab_mus_model.json new file mode 100644 index 0000000..c677fd8 --- /dev/null +++ b/resources/5cf1e9ab/5cf1e9ab_mus_model.json @@ -0,0 +1,41 @@ +{ +"music_data": +[ + [ + [ + [ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 1 ], + [ [ [ "Rest" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0 ], + [ [ [ 1, -1, 0, 0, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 2.625 ], + [ [ [ 1, -1, 0, 0, 0, 0 ], [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 2.875 ], + [ [ [ "Rest" ], [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0 ], + [ [ [ "Rest" ], [ -1, 0, 0, 0, 0, 1 ], [ "Rest" ], [ "Rest" ] ], 0 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 1.25 ] + ] + ] +], +"last_changes": +[ + [ [ 0, 1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], + [ [ 0, 1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 2, 0, 0, -2, -1, 0 ] ], + [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 2, 0, 0, -2, -1, 0 ] ], + [ [ 1, -1, 0, 0, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 2, 0, 0, -2, -1, 0 ] ], + [ [ 1, -1, 0, 0, 0, 0 ], [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ 2, 0, 0, -2, -1, 0 ] ] +], +"cur_uid": "5cf1e9ab", +"ref_uid": "640eeed3", +"order_seed": 747498, +"dur_seed": 968974, +"motifs_seed": 709945, +"entrances_probs_vals": [ 1, 0.5, 2, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.42746113989637, 0.77364864864865, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ], +"passages_probs_vals": [ 1, 1.87, 3.7996946564886, 0, 0.5, 0.5, 0.5, 1, 0.5 ], +"exits_probs_vals": [ 1, 0.5, 2, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.42746113989637, 0.77364864864865, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ], +"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ], +"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ], +"order": +[ + [ [ 2 ], [ 1, 0, 1 ], [ 3 ] ] +], +"sus_weights": [ 1, 0, 0 ], +"order_size": [ 1, 3 ], +"passages_size": [ 0, 2 ] +} \ No newline at end of file diff --git a/resources/5e947063/5e947063_code.scd b/resources/5e947063/5e947063_code.scd new file mode 100644 index 0000000..af06ede --- /dev/null +++ b/resources/5e947063/5e947063_code.scd @@ -0,0 +1,716 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck, +msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON; + +// model vars +//(model and global vars mostly set by OSC funcs +var curUID, refUID, orderSeed, durSeed, motifSeed, +entrancesProbVals, passagesProbVals, exitsProbVals, +ranges, orders, susWeights, passagesWeights, passagesSize, orderSize; + +// model aux vars +var entrancesDurFunc, passagesDurFunc, exitsDurFunc; + +// other global vars +var lastXChanges, popSize, exPath, dir, primes, dims, tuples, +seq, group, player, ledgerPath, ledger, currentlyPlayingUID; + + +// install JSON quark +if(Quarks.isInstalled("JSONlib").not, { + Quarks.install("https://github.com/musikinformatik/JSONlib.git"); + thisProcess.recompile; + //HelpBrowser.openHelpFor("Classes/JSONlib"); +}); + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genDurFunc = {arg chordProb, min, max, envData; + var env, pTable, durFunc; + env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + durFunc = {arg allowChord; + var res; + res = if(allowChord.not, { + pTable.tableRand * (max - min) + min + }, { + if(1.0.rand < chordProb, {0}, {pTable.tableRand * (max - min) + min}); + }).round(0.125); + if(res.asInteger == res, {res = res.asInteger}); + res + }; + seedFunc.value(durFunc, durSeed); +}; + +genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5; + ((maxMotifLength - minMotifLength).rand + minMotifLength).collect({ + var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order; + noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum); + noProgIns = (popSize - noSusIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] + }); +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = passagesWeights; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, flatOrder, res, isInChord, allowChord, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + flatOrder = silent ++ sus ++ prog; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + isInChord = popSize.collect({false}); + allowChord = false; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + flatOrder.do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + allowChord = if((sus ++ silent).includes(ins), { + (sus ++ silent).includes(ins) && (ins != sus.last); + }, { + if(i < (flatOrder.size - 1), {(isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not}, {false}); + }); + dur = passagesDurFunc.value(allowChord); + if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})}); + + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + + // pad ending + if(isLastOrder, { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + allowChord = (voices != popSize.collect({["Rest"]})); + dur = passagesDurFunc.value(allowChord); + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = { + var repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + + orders.do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~addr.sendMsg(~indexPath, ~indexMsg); + ~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3)); + //~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln); + }; +}); + +genPatterns = {arg inSeq, addr; + var voices, durs, patterns, res, indices, sectionDurs, ids, seq; + seq = inSeq.collect({arg mSeq; mSeq[0]}); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + indices = inSeq.collect({arg mSeq, m; mSeq[1]}); + ids = inSeq.collect({arg mSeq, m; mSeq[2]}); + sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum}); + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ) + }) ++ + [ + Pbind( + \type, \osc, + \addr, addr, + \indexPath, "/cur_play_index", + \indexMsg, Pseq(indices.postln, 1), + \seqPath, "/mus_seq", + \seqMsg, Pseq(seq, 1), + \dur, Pseq(sectionDurs, 1) + ); + ] + ); + res +}; + +/* +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; +*/ + + +//------resource management funcs + +genUID = {Date.seed.asHexString.toLower}; + +seedFunc = {arg func, seed; + var funcArgs, next; + next = Routine({loop{func.valueArray(funcArgs).yield }}); + next.randSeed_(seed); + {arg ...args; funcArgs = args; next.value} +}; + +stringifyToDepth = {arg data, maxDepth = 1; + var prettyString = "", rCount = 0, writeArray, indent; + + if(maxDepth == 0, { + data.asCompileString + }, { + indent = {arg size; size.collect({" "}).join("")}; + writeArray = {arg array; + prettyString = prettyString ++ indent.value(rCount) ++ "[\n"; + rCount = rCount + 1; + if(rCount < maxDepth, { + array.do({arg subArray; writeArray.value(subArray)}); + }, { + prettyString = prettyString ++ array.collect({arg subArray; + indent.value(rCount + 1) ++ subArray.asCompileString + }).join(",\n"); + }); + rCount = rCount - 1; + prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n"; + }; + + writeArray.value(data); + prettyString.replace(",\n\n", "\n").drop(-2); + }) +}; + +sanityCheck = {arg motif, index; + //print functions = very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true; + var res; + + res = in; + if(res.isNil.not, { + if((res.isArray && res.isString.not), { + res = res.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + if(escapeSingleQuotes, {res = res.replace("\'", "")}); + if(escapeDoubleQuotes, {res = res.replace("\"", "")}); + res = res.replace("Rest", "\"Rest\""); + res = res.interpret; + }, { + //res.postln; + if(res.every({arg char; char.isDecDigit}), {res = res.asInteger}); + }); + }); + res +}; + +writeResources = {arg path; + var file, nameSpaces, modelItems, resString; + file = File(path,"w"); + + nameSpaces = [ + "music_data", "last_changes", + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + modelItems = [ + seq, lastXChanges, + curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize + ]; + + resString = [nameSpaces, modelItems].flop.collect({arg item; + var nameSpace, modelItem, depth = 0, insert = " "; + # nameSpace, modelItem = item; + if(nameSpace == "music_data", {depth = 3; insert = "\n"}); + if(nameSpace == "last_changes", {depth = 1; insert = "\n"}); + if(nameSpace == "order", {depth = 1; insert = "\n"}); + "\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem.postln, depth).postln + }).join(",\n"); + + resString = "{\n" ++ resString ++ "\n}"; + + file.write(resString); + file.close; + resString +}; + +loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)}; + +loadModelJSON = {arg jsonObject; + var nameSpaces, data; + + //model = File(path, "r").readAllString.parseJSON; + + nameSpaces = [ + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + data = nameSpaces.collect({arg nS; msgInterpret.value(jsonObject[nS]).postln}); + + data.postln; + + # curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize = data; + + popSize = ranges.size; +}; + +loadLedgerFile = {arg path; + ledgerPath = path; + loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON) +}; + +loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]}; + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +//popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +//refUID = nil; +group = Group.new; +loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json"); +//passagesWeights = [1, 1, 1, 1, 1]; +//susWeights = [1, 1, 1]; + + +//------OSC funcs + +OSCdef(\load_ledger, {arg msg, time, addr, port; + loadLedgerFile.value(msg[1].asString); +}, \load_ledger); + +OSCdef(\load_model, {arg msg, time, addr, port; + loadModelFile.value(msg[1].asString); +}, \load_model); + + +OSCdef(\generate, {arg msg, time, addr, port; + var path, dFormat, condition, musPath, modelString; + msg.postln; + + path = msg[1].asString; + + loadModelFile.value(path); + + refUID.postln; + + loadLedgerFile.value(ledgerPath); + if(ledger == nil, {ledger = ["tmp"]}); + if(ledger.last != "tmp", {ledger = ledger.add("tmp")}); + + lastXChanges = if(refUID == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + refUID.postln; + file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..2] ++ [entrancesProbVals[3..]]); + passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..2] ++ [passagesProbVals[3..]]); + exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..2] ++ [exitsProbVals[3..]]); + + if(orders == nil, { + orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize); + //addr.sendMsg("/order", stringifyToDepth.value(orders, 1)); + }); + seq = seedFunc.value(genMotif, motifSeed).value; + + modelString = writeResources.value(path); + + //addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3)); + addr.sendMsg("/generated", path, modelString); +}, \generate); + + +OSCdef(\commit, {arg msg, time, addr, port; + var newLedger, modelPath, musString, musFile, test1, test2; + msg.postln; + + /* + test1 = msg[1].asString.parseJSON; + test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile; + msgInterpret.value(test1["music"])[0][0][0][1].class.postln; + msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln; + (test1["music"] == test2["music_data"]).postln; + */ + + curUID = genUID.value; + File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath); + File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath); + + modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; + writeResources.value(modelPath); + + File.delete(ledgerPath.postln ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath.postln, "w"); + ledger = ledger.postln.drop(-1).add(curUID); + newLedger.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}"); + newLedger.close; + + addr.sendMsg("/committed", curUID, ledgerPath); + //refUID = curUID; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + // the cued sequence can now be read from file, so this can be cleaned up + var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; + pSeq = []; + cuedSeek = (seq != nil); + indexStart = msg[2].asInteger; + indexEnd = ledger.size - if(cuedSeek, {2}, {1}); + ledger.postln; + if(((indexStart == (ledger.size - 1)) && cuedSeek).not, { + ledger[indexStart..indexEnd].do({arg uid, index; + var file; + (indexStart + index).postln; + file = File((dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), indexStart + index, uid]); + file.close; + }); + }); + if(cuedSeek, {pSeq = pSeq.add([seq, ledger.size - 1])}); + patterns = genPatterns.value(pSeq, addr); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; + +1223423434123.asHexString.toLower + +Date.getDate.rawSeconds +Date.seed.asHexString.toLower + +n = NetAddr("localhost", 8080); +n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals"); \ No newline at end of file diff --git a/resources/5e947063/5e947063_mus_model.json b/resources/5e947063/5e947063_mus_model.json new file mode 100644 index 0000000..a8164c4 --- /dev/null +++ b/resources/5e947063/5e947063_mus_model.json @@ -0,0 +1,48 @@ +{ +"music_data": +[ + [ + [ + [ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 2.875 ], + [ [ [ 1, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 1.875 ], + [ [ [ 1, 0, 0, 0, -1, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 2.25 ] + ], + [ + [ [ [ 1, 0, 0, 0, -1, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 2, 0, 0, -2, -1, 0 ] ], 1.875 ], + [ [ [ 1, 0, 0, 0, -1, 0 ], [ "Rest" ], [ 2, 0, 1, -2, -1, 0 ], [ 2, 0, 0, -2, -1, 0 ] ], 3.5 ], + [ [ [ 3, 0, -1, -2, -1, 0 ], [ "Rest" ], [ 2, 0, 1, -2, -1, 0 ], [ 2, 0, 0, -2, -1, 0 ] ], 2.375 ], + [ [ [ 3, 0, -1, -2, -1, 0 ], [ 2, 0, -1, -2, -1, 0 ], [ 2, 0, 1, -2, -1, 0 ], [ 2, 0, 0, -2, -1, 0 ] ], 2.5 ], + [ [ [ 3, 0, -1, -2, -1, 0 ], [ "Rest" ], [ 2, 0, 1, -2, -1, 0 ], [ 2, 0, 0, -2, -1, 0 ] ], 3.625 ], + [ [ [ 3, 0, -1, -2, -1, 0 ], [ "Rest" ], [ "Rest" ], [ 2, 0, 0, -2, -1, 0 ] ], 2.75 ], + [ [ [ 3, 0, -1, -2, -1, 0 ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 3.625 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 2.125 ] + ] + ] +], +"last_changes": +[ + [ [ 1, 0, -1, 0, 0, 0 ], [ 1, 0, 0, -1, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 2, 0, 0, -2, -1, 0 ] ], + [ [ 1, 0, 0, 0, -1, 0 ], [ 1, 0, 0, -1, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 2, 0, 0, -2, -1, 0 ] ], + [ [ 1, 0, 0, 0, -1, 0 ], [ 1, 0, 0, -1, -1, 0 ], [ 2, 0, 1, -2, -1, 0 ], [ 2, 0, 0, -2, -1, 0 ] ], + [ [ 3, 0, -1, -2, -1, 0 ], [ 1, 0, 0, -1, -1, 0 ], [ 2, 0, 1, -2, -1, 0 ], [ 2, 0, 0, -2, -1, 0 ] ], + [ [ 3, 0, -1, -2, -1, 0 ], [ 2, 0, -1, -2, -1, 0 ], [ 2, 0, 1, -2, -1, 0 ], [ 2, 0, 0, -2, -1, 0 ] ] +], +"cur_uid": "5e947063", +"ref_uid": "640eeed3", +"order_seed": 190057, +"dur_seed": 196835, +"motifs_seed": 211273, +"entrances_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"passages_probs_vals": [ 0, 1.87, 3.7996946564886, 0, 0.5, 0.5, 0.5, 1, 0.5 ], +"exits_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ], +"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ], +"order": +[ + [ [ 2 ], [ 0, 0 ], [ 3, 1 ] ], + [ [ 3 ], [ 2, 0, 1 ], [ ] ] +], +"sus_weights": [ 1, 0, 0 ], +"order_size": [ 1, 3 ], +"passages_size": [ 0, 2 ] +} \ No newline at end of file diff --git a/resources/628d5c8b/628d5c8b_code.scd b/resources/628d5c8b/628d5c8b_code.scd new file mode 100644 index 0000000..90f0b1e --- /dev/null +++ b/resources/628d5c8b/628d5c8b_code.scd @@ -0,0 +1,741 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck, +msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON; + +// model vars +//(model and global vars mostly set by OSC funcs +var curUID, refUID, orderSeed, durSeed, motifSeed, +entrancesProbVals, passagesProbVals, exitsProbVals, +ranges, orders, susWeights, passagesWeights, passagesSize, orderSize; + +// model aux vars +var entrancesDurFunc, passagesDurFunc, exitsDurFunc; + +// other global vars +var lastXChanges, popSize, exPath, dir, primes, dims, tuples, +seq, group, player, ledgerPath, ledger, currentlyPlayingUID; + + +// install JSON quark +if(Quarks.isInstalled("JSONlib").not, { + Quarks.install("https://github.com/musikinformatik/JSONlib.git"); + thisProcess.recompile; + //HelpBrowser.openHelpFor("Classes/JSONlib"); +}); + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genDurFunc = {arg chordProb, min, max, envData, seed; + var env, pTable, durFunc; + env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + durFunc = {arg allowChord; + var res; + res = if(allowChord.not, { + pTable.tableRand * (max - min) + min + }, { + if(1.0.rand < chordProb, {0}, {pTable.tableRand * (max - min) + min}); + }).round(0.125); + if(res.asInteger == res, {res = res.asInteger}); + res + }; + seedFunc.value(durFunc, seed); +}; + +genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5; + ((maxMotifLength - minMotifLength).rand + minMotifLength).collect({ + var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order; + noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum); + noProgIns = (popSize - noSusIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] + }); +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = passagesWeights; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, flatOrder, res, isInChord, allowChord, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + flatOrder = silent ++ sus ++ prog; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + isInChord = popSize.collect({false}); + allowChord = false; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + flatOrder.do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + + allowChord = if((sus ++ silent).includes(ins), { + //(sus ++ silent).includes(ins) && (ins != sus.last); + ins != sus.last; + }, { + if(i < (flatOrder.size - 1), {(isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not}, {false}); + }); + if((orderIndex == 0) && sus.includes(ins), { + dur = entrancesDurFunc.value(allowChord); + }, { + dur = passagesDurFunc.value(allowChord); + }); + //dur = passagesDurFunc.value(allowChord); + if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})}); + + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + + // pad ending + if(orderIndex == (orders.size - 1), { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + allowChord = (voices != popSize.collect({["Rest"]})); + dur = exitsDurFunc.value(allowChord); + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = { + var repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + + orders.do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +/* +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~addr.sendMsg(~indexPath, ~indexMsg); + ~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3)); + //~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln); + }; +}); +*/ + +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~msg.postln; + ~addr.sendMsg(~path, *~msg); + }; +}); + +genPatterns = {arg inSeq, addr; + var voices, durs, patterns, res, indices, sectionDurs, msg, ids, seq; + seq = inSeq.collect({arg mSeq; mSeq[0]}); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + msg = inSeq.collect({arg mSeq, m; mSeq[1..]}); + //ids = inSeq.collect({arg mSeq, m; mSeq[2]}); + sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum}); + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ) + }) ++ + [ + Pbind( + \type, \osc, + \addr, addr, + //\indexPath, "/cur_play_index", + //\indexMsg, Pseq(indices, 1), + //\seqPath, "/mus_seq", + //\seqMsg, Pseq(seq, 1), + \path, "/playing", + \msg, Pseq(msg, 1), + \dur, Pseq(sectionDurs, 1) + ); + ] + ); + res +}; + +/* +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; +*/ + + +//------resource management funcs + +genUID = {Date.seed.asHexString.toLower}; + +seedFunc = {arg func, seed; + var funcArgs, next; + next = Routine({loop{func.valueArray(funcArgs).yield }}); + next.randSeed_(seed); + {arg ...args; funcArgs = args; next.value} +}; + +stringifyToDepth = {arg data, maxDepth = 1; + var prettyString = "", rCount = 0, writeArray, indent; + + if(maxDepth == 0, { + data.asCompileString + }, { + indent = {arg size; size.collect({" "}).join("")}; + writeArray = {arg array; + prettyString = prettyString ++ indent.value(rCount) ++ "[\n"; + rCount = rCount + 1; + if(rCount < maxDepth, { + array.do({arg subArray; writeArray.value(subArray)}); + }, { + prettyString = prettyString ++ array.collect({arg subArray; + indent.value(rCount + 1) ++ subArray.asCompileString + }).join(",\n"); + }); + rCount = rCount - 1; + prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n"; + }; + + writeArray.value(data); + prettyString.replace(",\n\n", "\n").drop(-2); + }) +}; + +sanityCheck = {arg motif, index; + //print functions = very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true; + var res; + + res = in; + if(res.isNil.not, { + if((res.isArray && res.isString.not), { + res = res.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + if(escapeSingleQuotes, {res = res.replace("\'", "")}); + if(escapeDoubleQuotes, {res = res.replace("\"", "")}); + res = res.replace("Rest", "\"Rest\""); + res = res.interpret; + }, { + //res.postln; + if(res.every({arg char; char.isDecDigit}), {res = res.asInteger}); + }); + }); + res +}; + +writeResources = {arg path; + var file, nameSpaces, modelItems, resString; + file = File(path,"w"); + + nameSpaces = [ + "music_data", "last_changes", + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + modelItems = [ + seq, lastXChanges, + curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize + ]; + + resString = [nameSpaces, modelItems].flop.collect({arg item; + var nameSpace, modelItem, depth = 0, insert = " "; + # nameSpace, modelItem = item; + if(nameSpace == "music_data", {depth = 3; insert = "\n"}); + if(nameSpace == "last_changes", {depth = 1; insert = "\n"}); + if(nameSpace == "order", {depth = 1; insert = "\n"}); + if((nameSpace == "ref_uid") && (modelItem == nil), {modelItem = "nil"}); + "\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem, depth) + }).join(",\n"); + + resString = "{\n" ++ resString ++ "\n}"; + + file.write(resString); + file.close; + resString +}; + +loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)}; + +loadModelJSON = {arg jsonObject; + var nameSpaces, data; + + //model = File(path, "r").readAllString.parseJSON; + + nameSpaces = [ + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + data = nameSpaces.collect({arg nS; msgInterpret.value(jsonObject[nS])}); + + //data.postln; + + # curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize = data; + + popSize = ranges.size; +}; + +loadLedgerFile = {arg path; + ledgerPath = path; + loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON) +}; + +loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]}; + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +//popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +//refUID = nil; +group = Group.new; +loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json"); +//passagesWeights = [1, 1, 1, 1, 1]; +//susWeights = [1, 1, 1]; + + +//------OSC funcs + +OSCdef(\load_ledger, {arg msg, time, addr, port; + loadLedgerFile.value(msg[1].asString); +}, \load_ledger); + +OSCdef(\load_model, {arg msg, time, addr, port; + loadModelFile.value(msg[1].asString); +}, \load_model); + + +OSCdef(\generate, {arg msg, time, addr, port; + var path, durSeeds, musPath, modelString; + msg.postln; + + path = msg[1].asString; + + loadModelFile.value(path); + + //refUID.postln; + + loadLedgerFile.value(ledgerPath); + if(ledger == nil, {ledger = ["tmp"]}); + if(ledger.last != "tmp", {ledger = ledger.add("tmp")}); + + lastXChanges = if(refUID == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln; + entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..2] ++ [entrancesProbVals[3..]] ++ [durSeeds[0]]); + passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..2] ++ [passagesProbVals[3..]] ++ [durSeeds[1]]); + exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..2] ++ [exitsProbVals[3..]] ++ [durSeeds[2]]); + + if(orders == nil, { + orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize); + //addr.sendMsg("/order", stringifyToDepth.value(orders, 1)); + }); + seq = seedFunc.value(genMotif, motifSeed).value; + + modelString = writeResources.value(path); + + //addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3)); + addr.sendMsg("/generated", path, modelString); +}, \generate); + + +OSCdef(\commit, {arg msg, time, addr, port; + var newLedger, modelPath, musString, musFile, test1, test2; + msg.postln; + + /* + test1 = msg[1].asString.parseJSON; + test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile; + msgInterpret.value(test1["music"])[0][0][0][1].class.postln; + msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln; + (test1["music"] == test2["music_data"]).postln; + */ + + curUID = genUID.value; + File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath); + File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath); + + modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; + writeResources.value(modelPath); + + File.delete(ledgerPath ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath, "w"); + ledger = ledger.drop(-1).add(curUID); + newLedger.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}"); + newLedger.close; + + addr.sendMsg("/committed", curUID, ledgerPath); + //refUID = curUID; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + // the cued sequence can now be read from file, so this can be cleaned up + var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; + pSeq = []; + cuedSeek = (seq != nil); + indexStart = msg[2].asInteger; + indexEnd = ledger.size - if(cuedSeek, {2}, {1}); + //ledger.postln; + if(((indexStart == (ledger.size - 1)) && cuedSeek).not, { + ledger[indexStart..indexEnd].do({arg uid, index; + var path, file; + path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath; + file = File(path, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, indexStart + index, uid]); + file.close; + }); + }); + if(cuedSeek, { + var path, file; + path = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath; + file = File(path, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]); + file.close; + }); + patterns = genPatterns.value(pSeq, addr); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; + +1223423434123.asHexString.toLower + +Date.getDate.rawSeconds +Date.seed.asHexString.toLower + +n = NetAddr("localhost", 8080); +n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals"); \ No newline at end of file diff --git a/resources/628d5c8b/628d5c8b_mus_model.json b/resources/628d5c8b/628d5c8b_mus_model.json new file mode 100644 index 0000000..a7c647e --- /dev/null +++ b/resources/628d5c8b/628d5c8b_mus_model.json @@ -0,0 +1,56 @@ +{ +"music_data": +[ + [ + [ + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 0.625 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 0, 1, 0, 0, 0, 0 ] ], 0 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 1, 0, 0, 0, 0 ] ], 1.75 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 1, 0, 0, 0, 0, -1 ], [ 1, 0, 0, 0, -1, 0 ] ], 1.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 1, 0 ] ], 1.5 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 1, 0, 0, 0 ] ], 0.75 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 1, 0, 0, 0, 0, -1 ], [ 1, 0, 0, -1, 0, 0 ] ], 1.25 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 1, 0, 0, 0, 0, -1 ], [ -1, 0, 0, 1, 0, 0 ] ], 1.625 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 1, 0, 0, 0, 0 ] ], 1.875 ] + ], + [ + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 1, 0, 0, 0, 0 ] ], 1 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ], [ 0, 1, 0, 0, 0, 0 ] ], 1.125 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 1, -1, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0 ] ], 0.75 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 1, 0, 0, -1, 0 ], [ 0, 1, 0, 0, 0, 0 ] ], 1.5 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 1 ], [ 0, 1, 0, 0, 0, 0 ] ], 1.5 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, -1 ], [ 0, 1, 0, 0, 0, 0 ] ], 1.75 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 1, 0, 0, 0, 0 ] ], 1.125 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0.5 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 0 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 1.25 ] + ] + ] +], +"last_changes": +[ + [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ], [ 0, 1, 0, 0, 0, 0 ] ], + [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 1, -1, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0 ] ], + [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 1, 0, 0, -1, 0 ], [ 0, 1, 0, 0, 0, 0 ] ], + [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 1 ], [ 0, 1, 0, 0, 0, 0 ] ], + [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, -1 ], [ 0, 1, 0, 0, 0, 0 ] ] +], +"cur_uid": "628d5c8b", +"ref_uid": "7e170ef8", +"order_seed": 227004, +"dur_seed": 357129, +"motifs_seed": 170994, +"entrances_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ], +"passages_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"exits_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"ranges": [ [ 65, 727 ], [ 799, 1758 ], [ -282, 1013 ], [ -282, 799 ] ], +"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ], +"order": +[ + [ [ 0 ], [ 3, 2, 3, 3, 3, 3, 3, 3 ], [ 1 ] ], + [ [ 0, 3, 1 ], [ 2, 2, 2, 2, 2 ], [ ] ] +], +"sus_weights": [ 0.75, 0.69, 0.75 ], +"order_size": [ 2, 6 ], +"passages_size": [ 0, 10 ] +} \ No newline at end of file diff --git a/resources/62b894e8/62b894e8_code.scd b/resources/62b894e8/62b894e8_code.scd new file mode 100644 index 0000000..70e0740 --- /dev/null +++ b/resources/62b894e8/62b894e8_code.scd @@ -0,0 +1,735 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck, +msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON; + +// model vars +//(model and global vars mostly set by OSC funcs +var curUID, refUID, orderSeed, durSeed, motifSeed, +entrancesProbVals, passagesProbVals, exitsProbVals, +ranges, orders, susWeights, passagesWeights, passagesSize, orderSize; + +// model aux vars +var entrancesDurFunc, passagesDurFunc, exitsDurFunc; + +// other global vars +var lastXChanges, popSize, exPath, dir, primes, dims, tuples, +seq, group, player, ledgerPath, ledger, currentlyPlayingUID; + + +// install JSON quark +if(Quarks.isInstalled("JSONlib").not, { + Quarks.install("https://github.com/musikinformatik/JSONlib.git"); + thisProcess.recompile; + //HelpBrowser.openHelpFor("Classes/JSONlib"); +}); + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genDurFunc = {arg chordProb, min, max, envData, seed; + var env, pTable, durFunc; + env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + durFunc = {arg allowChord; + var res; + res = if(allowChord.not, { + pTable.tableRand * (max - min) + min + }, { + if(1.0.rand < chordProb, {0}, {pTable.tableRand * (max - min) + min}); + }).round(0.125); + if(res.asInteger == res, {res = res.asInteger}); + res + }; + seedFunc.value(durFunc, seed); +}; + +genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5; + ((maxMotifLength - minMotifLength).rand + minMotifLength).collect({ + var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order; + noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum); + noProgIns = (popSize - noSusIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] + }); +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = passagesWeights; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, flatOrder, res, isInChord, allowChord, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + flatOrder = silent ++ sus ++ prog; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + isInChord = popSize.collect({false}); + allowChord = false; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + flatOrder.do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + + allowChord = if((sus ++ silent).includes(ins), { + //(sus ++ silent).includes(ins) && (ins != sus.last); + ins != sus.last; + }, { + if(i < (flatOrder.size - 1), {(isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not}, {false}); + }); + if((orderIndex == 0) && sus.includes(ins), { + dur = entrancesDurFunc.value(allowChord); + }, { + dur = passagesDurFunc.value(allowChord); + }); + //dur = passagesDurFunc.value(allowChord); + if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})}); + + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + + // pad ending + if(orderIndex == (orders.size - 1), { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + allowChord = (voices != popSize.collect({["Rest"]})); + dur = exitsDurFunc.value(allowChord); + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = { + var repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + + orders.do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +/* +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~addr.sendMsg(~indexPath, ~indexMsg); + ~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3)); + //~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln); + }; +}); +*/ + +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~msg.postln; + ~addr.sendMsg(~path, *~msg); + }; +}); + +genPatterns = {arg inSeq, addr; + var voices, durs, patterns, res, indices, sectionDurs, msg, ids, seq; + seq = inSeq.collect({arg mSeq; mSeq[0]}); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + msg = inSeq.collect({arg mSeq, m; mSeq[1..]}); + //ids = inSeq.collect({arg mSeq, m; mSeq[2]}); + sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum}); + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ) + }) ++ + [ + Pbind( + \type, \osc, + \addr, addr, + //\indexPath, "/cur_play_index", + //\indexMsg, Pseq(indices, 1), + //\seqPath, "/mus_seq", + //\seqMsg, Pseq(seq, 1), + \path, "/playing", + \msg, Pseq(msg, 1), + \dur, Pseq(sectionDurs, 1) + ); + ] + ); + res +}; + +/* +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; +*/ + + +//------resource management funcs + +genUID = {Date.seed.asHexString.toLower}; + +seedFunc = {arg func, seed; + var funcArgs, next; + next = Routine({loop{func.valueArray(funcArgs).yield }}); + next.randSeed_(seed); + {arg ...args; funcArgs = args; next.value} +}; + +stringifyToDepth = {arg data, maxDepth = 1; + var prettyString = "", rCount = 0, writeArray, indent; + + if(maxDepth == 0, { + data.asCompileString + }, { + indent = {arg size; size.collect({" "}).join("")}; + writeArray = {arg array; + prettyString = prettyString ++ indent.value(rCount) ++ "[\n"; + rCount = rCount + 1; + if(rCount < maxDepth, { + array.do({arg subArray; writeArray.value(subArray)}); + }, { + prettyString = prettyString ++ array.collect({arg subArray; + indent.value(rCount + 1) ++ subArray.asCompileString + }).join(",\n"); + }); + rCount = rCount - 1; + prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n"; + }; + + writeArray.value(data); + prettyString.replace(",\n\n", "\n").drop(-2); + }) +}; + +sanityCheck = {arg motif, index; + //print functions = very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true; + var res; + + res = in; + if(res.isNil.not, { + if((res.isArray && res.isString.not), { + res = res.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + if(escapeSingleQuotes, {res = res.replace("\'", "")}); + if(escapeDoubleQuotes, {res = res.replace("\"", "")}); + res = res.replace("Rest", "\"Rest\""); + res = res.interpret; + }, { + //res.postln; + if(res.every({arg char; char.isDecDigit}), {res = res.asInteger}); + }); + }); + res +}; + +writeResources = {arg path; + var file, nameSpaces, modelItems, resString; + file = File(path,"w"); + + nameSpaces = [ + "music_data", "last_changes", + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + modelItems = [ + seq, lastXChanges, + curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize + ]; + + resString = [nameSpaces, modelItems].flop.collect({arg item; + var nameSpace, modelItem, depth = 0, insert = " "; + # nameSpace, modelItem = item; + if(nameSpace == "music_data", {depth = 3; insert = "\n"}); + if(nameSpace == "last_changes", {depth = 1; insert = "\n"}); + if(nameSpace == "order", {depth = 1; insert = "\n"}); + if((nameSpace == "ref_uid") && (modelItem == nil), {modelItem = "nil"}); + "\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem, depth) + }).join(",\n"); + + resString = "{\n" ++ resString ++ "\n}"; + + file.write(resString); + file.close; + resString +}; + +loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)}; + +loadModelJSON = {arg jsonObject; + var nameSpaces, data; + + //model = File(path, "r").readAllString.parseJSON; + + nameSpaces = [ + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + data = nameSpaces.collect({arg nS; msgInterpret.value(jsonObject[nS])}); + + //data.postln; + + # curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize = data; + + popSize = ranges.size; +}; + +loadLedgerFile = {arg path; + ledgerPath = path; + loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON) +}; + +loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]}; + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +//popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +//refUID = nil; +group = Group.new; +loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json"); +//passagesWeights = [1, 1, 1, 1, 1]; +//susWeights = [1, 1, 1]; + + +//------OSC funcs + +OSCdef(\load_ledger, {arg msg, time, addr, port; + loadLedgerFile.value(msg[1].asString); +}, \load_ledger); + +OSCdef(\load_model, {arg msg, time, addr, port; + loadModelFile.value(msg[1].asString); +}, \load_model); + + +OSCdef(\generate, {arg msg, time, addr, port; + var path, durSeeds, musPath, modelString; + msg.postln; + + path = msg[1].asString; + + loadModelFile.value(path); + + //refUID.postln; + + loadLedgerFile.value(ledgerPath); + if(ledger == nil, {ledger = ["tmp"]}); + if(ledger.last != "tmp", {ledger = ledger.add("tmp")}); + + lastXChanges = if(refUID == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln; + entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..2] ++ [entrancesProbVals[3..]] ++ [durSeeds[0]]); + passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..2] ++ [passagesProbVals[3..]] ++ [durSeeds[1]]); + exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..2] ++ [exitsProbVals[3..]] ++ [durSeeds[2]]); + + if(orders == nil, { + orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize); + //addr.sendMsg("/order", stringifyToDepth.value(orders, 1)); + }); + seq = seedFunc.value(genMotif, motifSeed).value; + + modelString = writeResources.value(path); + + //addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3)); + addr.sendMsg("/generated", path, modelString); +}, \generate); + + +OSCdef(\commit, {arg msg, time, addr, port; + var newLedger, modelPath, musString, musFile, test1, test2; + msg.postln; + + /* + test1 = msg[1].asString.parseJSON; + test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile; + msgInterpret.value(test1["music"])[0][0][0][1].class.postln; + msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln; + (test1["music"] == test2["music_data"]).postln; + */ + + curUID = genUID.value; + File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath); + File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath); + + modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; + writeResources.value(modelPath); + + File.delete(ledgerPath ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath, "w"); + ledger = ledger.drop(-1).add(curUID); + newLedger.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}"); + newLedger.close; + + addr.sendMsg("/committed", curUID, ledgerPath); + //refUID = curUID; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + // the cued sequence can now be read from file, so this can be cleaned up + var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; + pSeq = []; + cuedSeek = (seq != nil); + indexStart = msg[2].asInteger; + indexEnd = ledger.size - if(cuedSeek, {2}, {1}); + //ledger.postln; + if(((indexStart == (ledger.size - 1)) && cuedSeek).not, { + ledger[indexStart..indexEnd].do({arg uid, index; + var path, file; + path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath; + file = File(path, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, indexStart + index, uid]); + file.close; + }); + }); + if(cuedSeek, {pSeq = pSeq.add([seq, ledger.size - 1])}); + patterns = genPatterns.value(pSeq, addr); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; + +1223423434123.asHexString.toLower + +Date.getDate.rawSeconds +Date.seed.asHexString.toLower + +n = NetAddr("localhost", 8080); +n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals"); \ No newline at end of file diff --git a/resources/62b894e8/62b894e8_mus_model.json b/resources/62b894e8/62b894e8_mus_model.json new file mode 100644 index 0000000..3b411ce --- /dev/null +++ b/resources/62b894e8/62b894e8_mus_model.json @@ -0,0 +1,91 @@ +{ +"music_data": +[ + [ + [ + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 0.75 ], + [ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.625 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.375 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.75 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.625 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.5 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.25 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.375 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.625 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.375 ] + ], + [ + [ [ [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0 ], + [ [ [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 0 ], + [ [ [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 1.375 ], + [ [ [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 1, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ] ], 1.625 ], + [ [ [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ] ], 0 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ] ], 0 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 1, 0 ] ], 1.5 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, 0, 0 ] ], 1.5 ] + ], + [ + [ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, 0, 0 ] ], 0 ], + [ [ [ "Rest" ], [ 1, 0, 0, 0, -2, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, 0, 0 ] ], 0.625 ], + [ [ [ "Rest" ], [ 1, 0, 0, 0, -2, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 1, -1, 0 ] ], 1.375 ], + [ [ [ "Rest" ], [ 1, 0, 0, 0, -2, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 1 ] ], 0.625 ], + [ [ [ "Rest" ], [ 1, 0, 0, 0, -2, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ 0, 1, 0, 0, -1, 0 ] ], 1.875 ], + [ [ [ "Rest" ], [ 1, 0, 0, 0, -2, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0 ], + [ [ [ "Rest" ], [ 1, -1, 0, 0, -1, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.375 ], + [ [ [ "Rest" ], [ 1, -1, 0, 0, -1, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ 1, 0, 0, 0, -2, 0 ] ], 0 ], + [ [ [ "Rest" ], [ 1, 0, 0, 0, -1, -1 ], [ 1, 0, 0, 0, -1, 0 ], [ 1, 0, 0, 0, -2, 0 ] ], 1.75 ], + [ [ [ "Rest" ], [ 1, 0, 0, -1, -1, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ 1, 0, 0, 0, -2, 0 ] ], 1.875 ] + ], + [ + [ [ [ -1, 0, 0, 0, 0, 1 ], [ 1, 0, 0, -1, -1, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ 1, 0, 0, 0, -2, 0 ] ], 1.125 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ 1, 0, 0, -1, -1, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ -1, 0, 1, 0, 0, 1 ] ], 0 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, -1, 0, 1 ], [ 1, 0, 0, 0, -1, 0 ], [ -1, 0, 1, 0, 0, 1 ] ], 1.875 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, -1, 0, 1 ], [ -1, 0, 0, 1, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ] ], 1.5 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, -1, 0, 1 ], [ 0, 0, -1, 0, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ] ], 0 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, -1, 0, 1 ], [ 0, 0, -1, 0, 0, 1 ], [ 0, -1, 0, 0, 0, 1 ] ], 0.75 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, -1, 0, 1 ], [ 0, 0, -1, 0, 0, 1 ], [ -1, 1, 0, 0, 0, 1 ] ], 0 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ], [ 0, 0, -1, 0, 0, 1 ], [ -1, 1, 0, 0, 0, 1 ] ], 1.75 ] + ], + [ + [ [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ], [ 0, 0, -1, 0, 0, 1 ], [ "Rest" ] ], 0 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ], [ -1, 0, 1, 0, 1, 1 ], [ "Rest" ] ], 1.25 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ], [ -1, 0, 0, 0, 0, 2 ], [ "Rest" ] ], 1.5 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ], [ 0, 0, 0, 0, -1, 1 ], [ "Rest" ] ], 1.75 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.75 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ], [ 0, -1, 0, 0, 0, 1 ], [ "Rest" ] ], 1.75 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ], [ "Rest" ], [ "Rest" ] ], 1 ], + [ [ [ -1, 0, 0, 0, 0, 1 ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 0.75 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 1.25 ] + ] + ] +], +"last_changes": +[ + [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ], [ -1, 0, 1, 0, 1, 1 ], [ -1, 1, 0, 0, 0, 1 ] ], + [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ], [ -1, 0, 0, 0, 0, 2 ], [ -1, 1, 0, 0, 0, 1 ] ], + [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ], [ 0, 0, 0, 0, -1, 1 ], [ -1, 1, 0, 0, 0, 1 ] ], + [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 1 ] ], + [ [ -1, 0, 0, 0, 0, 1 ], [ -1, 0, 1, 0, 0, 1 ], [ 0, -1, 0, 0, 0, 1 ], [ -1, 1, 0, 0, 0, 1 ] ] +], +"cur_uid": "62b894e8", +"ref_uid": "nil", +"order_seed": 684642, +"dur_seed": 712392, +"motifs_seed": 330807, +"entrances_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ], +"passages_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"exits_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ], +"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ], +"order": +[ + [ [ 3, 1, 0 ], [ 2, 2, 2, 2, 2, 2, 2 ], [ ] ], + [ [ 1 ], [ 0, 3, 2, 3, 3, 0, 2, 3 ], [ ] ], + [ [ 2 ], [ 1, 3, 3, 3, 3, 1, 3, 1, 1 ], [ 0 ] ], + [ [ 0 ], [ 3, 1, 2, 2, 3, 3, 1 ], [ ] ], + [ [ 1, 0 ], [ 2, 2, 2, 2, 2 ], [ 3 ] ] +], +"sus_weights": [ 0.75, 0.69, 0.75 ], +"order_size": [ 2, 6 ], +"passages_size": [ 0, 10 ] +} \ No newline at end of file diff --git a/resources/640eeed3/640eeed3_code.scd b/resources/640eeed3/640eeed3_code.scd new file mode 100644 index 0000000..af06ede --- /dev/null +++ b/resources/640eeed3/640eeed3_code.scd @@ -0,0 +1,716 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck, +msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON; + +// model vars +//(model and global vars mostly set by OSC funcs +var curUID, refUID, orderSeed, durSeed, motifSeed, +entrancesProbVals, passagesProbVals, exitsProbVals, +ranges, orders, susWeights, passagesWeights, passagesSize, orderSize; + +// model aux vars +var entrancesDurFunc, passagesDurFunc, exitsDurFunc; + +// other global vars +var lastXChanges, popSize, exPath, dir, primes, dims, tuples, +seq, group, player, ledgerPath, ledger, currentlyPlayingUID; + + +// install JSON quark +if(Quarks.isInstalled("JSONlib").not, { + Quarks.install("https://github.com/musikinformatik/JSONlib.git"); + thisProcess.recompile; + //HelpBrowser.openHelpFor("Classes/JSONlib"); +}); + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genDurFunc = {arg chordProb, min, max, envData; + var env, pTable, durFunc; + env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + durFunc = {arg allowChord; + var res; + res = if(allowChord.not, { + pTable.tableRand * (max - min) + min + }, { + if(1.0.rand < chordProb, {0}, {pTable.tableRand * (max - min) + min}); + }).round(0.125); + if(res.asInteger == res, {res = res.asInteger}); + res + }; + seedFunc.value(durFunc, durSeed); +}; + +genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5; + ((maxMotifLength - minMotifLength).rand + minMotifLength).collect({ + var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order; + noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum); + noProgIns = (popSize - noSusIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] + }); +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = passagesWeights; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, flatOrder, res, isInChord, allowChord, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + flatOrder = silent ++ sus ++ prog; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + isInChord = popSize.collect({false}); + allowChord = false; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + flatOrder.do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + allowChord = if((sus ++ silent).includes(ins), { + (sus ++ silent).includes(ins) && (ins != sus.last); + }, { + if(i < (flatOrder.size - 1), {(isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not}, {false}); + }); + dur = passagesDurFunc.value(allowChord); + if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})}); + + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + + // pad ending + if(isLastOrder, { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + allowChord = (voices != popSize.collect({["Rest"]})); + dur = passagesDurFunc.value(allowChord); + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = { + var repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + + orders.do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~addr.sendMsg(~indexPath, ~indexMsg); + ~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3)); + //~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln); + }; +}); + +genPatterns = {arg inSeq, addr; + var voices, durs, patterns, res, indices, sectionDurs, ids, seq; + seq = inSeq.collect({arg mSeq; mSeq[0]}); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + indices = inSeq.collect({arg mSeq, m; mSeq[1]}); + ids = inSeq.collect({arg mSeq, m; mSeq[2]}); + sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum}); + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ) + }) ++ + [ + Pbind( + \type, \osc, + \addr, addr, + \indexPath, "/cur_play_index", + \indexMsg, Pseq(indices.postln, 1), + \seqPath, "/mus_seq", + \seqMsg, Pseq(seq, 1), + \dur, Pseq(sectionDurs, 1) + ); + ] + ); + res +}; + +/* +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; +*/ + + +//------resource management funcs + +genUID = {Date.seed.asHexString.toLower}; + +seedFunc = {arg func, seed; + var funcArgs, next; + next = Routine({loop{func.valueArray(funcArgs).yield }}); + next.randSeed_(seed); + {arg ...args; funcArgs = args; next.value} +}; + +stringifyToDepth = {arg data, maxDepth = 1; + var prettyString = "", rCount = 0, writeArray, indent; + + if(maxDepth == 0, { + data.asCompileString + }, { + indent = {arg size; size.collect({" "}).join("")}; + writeArray = {arg array; + prettyString = prettyString ++ indent.value(rCount) ++ "[\n"; + rCount = rCount + 1; + if(rCount < maxDepth, { + array.do({arg subArray; writeArray.value(subArray)}); + }, { + prettyString = prettyString ++ array.collect({arg subArray; + indent.value(rCount + 1) ++ subArray.asCompileString + }).join(",\n"); + }); + rCount = rCount - 1; + prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n"; + }; + + writeArray.value(data); + prettyString.replace(",\n\n", "\n").drop(-2); + }) +}; + +sanityCheck = {arg motif, index; + //print functions = very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true; + var res; + + res = in; + if(res.isNil.not, { + if((res.isArray && res.isString.not), { + res = res.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + if(escapeSingleQuotes, {res = res.replace("\'", "")}); + if(escapeDoubleQuotes, {res = res.replace("\"", "")}); + res = res.replace("Rest", "\"Rest\""); + res = res.interpret; + }, { + //res.postln; + if(res.every({arg char; char.isDecDigit}), {res = res.asInteger}); + }); + }); + res +}; + +writeResources = {arg path; + var file, nameSpaces, modelItems, resString; + file = File(path,"w"); + + nameSpaces = [ + "music_data", "last_changes", + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + modelItems = [ + seq, lastXChanges, + curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize + ]; + + resString = [nameSpaces, modelItems].flop.collect({arg item; + var nameSpace, modelItem, depth = 0, insert = " "; + # nameSpace, modelItem = item; + if(nameSpace == "music_data", {depth = 3; insert = "\n"}); + if(nameSpace == "last_changes", {depth = 1; insert = "\n"}); + if(nameSpace == "order", {depth = 1; insert = "\n"}); + "\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem.postln, depth).postln + }).join(",\n"); + + resString = "{\n" ++ resString ++ "\n}"; + + file.write(resString); + file.close; + resString +}; + +loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)}; + +loadModelJSON = {arg jsonObject; + var nameSpaces, data; + + //model = File(path, "r").readAllString.parseJSON; + + nameSpaces = [ + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + data = nameSpaces.collect({arg nS; msgInterpret.value(jsonObject[nS]).postln}); + + data.postln; + + # curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize = data; + + popSize = ranges.size; +}; + +loadLedgerFile = {arg path; + ledgerPath = path; + loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON) +}; + +loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]}; + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +//popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +//refUID = nil; +group = Group.new; +loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json"); +//passagesWeights = [1, 1, 1, 1, 1]; +//susWeights = [1, 1, 1]; + + +//------OSC funcs + +OSCdef(\load_ledger, {arg msg, time, addr, port; + loadLedgerFile.value(msg[1].asString); +}, \load_ledger); + +OSCdef(\load_model, {arg msg, time, addr, port; + loadModelFile.value(msg[1].asString); +}, \load_model); + + +OSCdef(\generate, {arg msg, time, addr, port; + var path, dFormat, condition, musPath, modelString; + msg.postln; + + path = msg[1].asString; + + loadModelFile.value(path); + + refUID.postln; + + loadLedgerFile.value(ledgerPath); + if(ledger == nil, {ledger = ["tmp"]}); + if(ledger.last != "tmp", {ledger = ledger.add("tmp")}); + + lastXChanges = if(refUID == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + refUID.postln; + file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..2] ++ [entrancesProbVals[3..]]); + passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..2] ++ [passagesProbVals[3..]]); + exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..2] ++ [exitsProbVals[3..]]); + + if(orders == nil, { + orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize); + //addr.sendMsg("/order", stringifyToDepth.value(orders, 1)); + }); + seq = seedFunc.value(genMotif, motifSeed).value; + + modelString = writeResources.value(path); + + //addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3)); + addr.sendMsg("/generated", path, modelString); +}, \generate); + + +OSCdef(\commit, {arg msg, time, addr, port; + var newLedger, modelPath, musString, musFile, test1, test2; + msg.postln; + + /* + test1 = msg[1].asString.parseJSON; + test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile; + msgInterpret.value(test1["music"])[0][0][0][1].class.postln; + msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln; + (test1["music"] == test2["music_data"]).postln; + */ + + curUID = genUID.value; + File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath); + File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath); + + modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; + writeResources.value(modelPath); + + File.delete(ledgerPath.postln ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath.postln, "w"); + ledger = ledger.postln.drop(-1).add(curUID); + newLedger.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}"); + newLedger.close; + + addr.sendMsg("/committed", curUID, ledgerPath); + //refUID = curUID; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + // the cued sequence can now be read from file, so this can be cleaned up + var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; + pSeq = []; + cuedSeek = (seq != nil); + indexStart = msg[2].asInteger; + indexEnd = ledger.size - if(cuedSeek, {2}, {1}); + ledger.postln; + if(((indexStart == (ledger.size - 1)) && cuedSeek).not, { + ledger[indexStart..indexEnd].do({arg uid, index; + var file; + (indexStart + index).postln; + file = File((dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), indexStart + index, uid]); + file.close; + }); + }); + if(cuedSeek, {pSeq = pSeq.add([seq, ledger.size - 1])}); + patterns = genPatterns.value(pSeq, addr); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; + +1223423434123.asHexString.toLower + +Date.getDate.rawSeconds +Date.seed.asHexString.toLower + +n = NetAddr("localhost", 8080); +n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals"); \ No newline at end of file diff --git a/resources/640eeed3/640eeed3_mus_model.json b/resources/640eeed3/640eeed3_mus_model.json new file mode 100644 index 0000000..79d175f --- /dev/null +++ b/resources/640eeed3/640eeed3_mus_model.json @@ -0,0 +1,38 @@ +{ +"music_data": +[ + [ + [ + [ [ [ "Rest" ], [ 1, 0, 0, -1, -1, 0 ], [ "Rest" ], [ "Rest" ] ], 3.125 ], + [ [ [ "Rest" ], [ 1, 0, 0, -1, -1, 0 ], [ "Rest" ], [ 2, 0, 0, -2, -1, 0 ] ], 2.25 ], + [ [ [ "Rest" ], [ 1, 0, 0, -1, -1, 0 ], [ "Rest" ], [ "Rest" ] ], 2.625 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 2 ] + ] + ] +], +"last_changes": +[ + [ [ 0, 1, 0, 0, 0, 0 ], [ 0, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], + [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], + [ [ 0, 1, 0, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], + [ [ 0, 1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], + [ [ 0, 1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 2, 0, 0, -2, -1, 0 ] ] +], +"cur_uid": "640eeed3", +"ref_uid": "4c01589b", +"order_seed": 155513, +"dur_seed": 460216, +"motifs_seed": 397643, +"entrances_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"passages_probs_vals": [ 0, 1.87, 3.7996946564886, 0, 0.5, 0.5, 0.5, 1, 0.5 ], +"exits_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ], +"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ], +"order": +[ + [ [ 1 ], [ 3 ], [ 0, 2 ] ] +], +"sus_weights": [ 1, 0, 0 ], +"order_size": [ 1, 3 ], +"passages_size": [ 0, 2 ] +} \ No newline at end of file diff --git a/resources/7aa8c429/7aa8c429_code.scd b/resources/7aa8c429/7aa8c429_code.scd new file mode 100644 index 0000000..b6ff291 --- /dev/null +++ b/resources/7aa8c429/7aa8c429_code.scd @@ -0,0 +1,734 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck, +msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON; + +// model vars +//(model and global vars mostly set by OSC funcs +var curUID, refUID, orderSeed, durSeed, motifSeed, +entrancesProbVals, passagesProbVals, exitsProbVals, +ranges, orders, susWeights, passagesWeights, passagesSize, orderSize; + +// model aux vars +var entrancesDurFunc, passagesDurFunc, exitsDurFunc; + +// other global vars +var lastXChanges, popSize, exPath, dir, primes, dims, tuples, +seq, group, player, ledgerPath, ledger, currentlyPlayingUID; + + +// install JSON quark +if(Quarks.isInstalled("JSONlib").not, { + Quarks.install("https://github.com/musikinformatik/JSONlib.git"); + thisProcess.recompile; + //HelpBrowser.openHelpFor("Classes/JSONlib"); +}); + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genDurFunc = {arg chordProb, min, max, envData, seed; + var env, pTable, durFunc; + env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + durFunc = {arg allowChord; + var res; + res = if(allowChord.not, { + pTable.tableRand * (max - min) + min + }, { + if(1.0.rand < chordProb, {0}, {pTable.tableRand * (max - min) + min}); + }).round(0.125); + if(res.asInteger == res, {res = res.asInteger}); + res + }; + seedFunc.value(durFunc, seed); +}; + +genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5; + ((maxMotifLength - minMotifLength).rand + minMotifLength).collect({ + var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order; + noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum); + noProgIns = (popSize - noSusIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] + }); +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = passagesWeights; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, flatOrder, res, isInChord, allowChord, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + flatOrder = silent ++ sus ++ prog; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + isInChord = popSize.collect({false}); + allowChord = false; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + flatOrder.do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + + allowChord = if((sus ++ silent).includes(ins), { + //(sus ++ silent).includes(ins) && (ins != sus.last); + ins != sus.last; + }, { + if(i < (flatOrder.size - 1), {(isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not}, {false}); + }); + if((orderIndex == 0) && sus.includes(ins), { + dur = entrancesDurFunc.value(allowChord); + }, { + dur = passagesDurFunc.value(allowChord); + }); + //dur = passagesDurFunc.value(allowChord); + if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})}); + + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + + // pad ending + if(orderIndex == (orders.size - 1), { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + allowChord = (voices != popSize.collect({["Rest"]})); + dur = exitsDurFunc.value(allowChord); + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = { + var repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + + orders.do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +/* +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~addr.sendMsg(~indexPath, ~indexMsg); + ~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3)); + //~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln); + }; +}); +*/ + +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~msg.postln; + ~addr.sendMsg(~path, *~msg); + }; +}); + +genPatterns = {arg inSeq, addr; + var voices, durs, patterns, res, indices, sectionDurs, msg, ids, seq; + seq = inSeq.collect({arg mSeq; mSeq[0]}); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + msg = inSeq.collect({arg mSeq, m; mSeq[1..]}); + //ids = inSeq.collect({arg mSeq, m; mSeq[2]}); + sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum}); + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ) + }) ++ + [ + Pbind( + \type, \osc, + \addr, addr, + //\indexPath, "/cur_play_index", + //\indexMsg, Pseq(indices, 1), + //\seqPath, "/mus_seq", + //\seqMsg, Pseq(seq, 1), + \path, "/playing", + \msg, Pseq(msg, 1), + \dur, Pseq(sectionDurs, 1) + ); + ] + ); + res +}; + +/* +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; +*/ + + +//------resource management funcs + +genUID = {Date.seed.asHexString.toLower}; + +seedFunc = {arg func, seed; + var funcArgs, next; + next = Routine({loop{func.valueArray(funcArgs).yield }}); + next.randSeed_(seed); + {arg ...args; funcArgs = args; next.value} +}; + +stringifyToDepth = {arg data, maxDepth = 1; + var prettyString = "", rCount = 0, writeArray, indent; + + if(maxDepth == 0, { + data.asCompileString + }, { + indent = {arg size; size.collect({" "}).join("")}; + writeArray = {arg array; + prettyString = prettyString ++ indent.value(rCount) ++ "[\n"; + rCount = rCount + 1; + if(rCount < maxDepth, { + array.do({arg subArray; writeArray.value(subArray)}); + }, { + prettyString = prettyString ++ array.collect({arg subArray; + indent.value(rCount + 1) ++ subArray.asCompileString + }).join(",\n"); + }); + rCount = rCount - 1; + prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n"; + }; + + writeArray.value(data); + prettyString.replace(",\n\n", "\n").drop(-2); + }) +}; + +sanityCheck = {arg motif, index; + //print functions = very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true; + var res; + + res = in; + if(res.isNil.not, { + if((res.isArray && res.isString.not), { + res = res.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + if(escapeSingleQuotes, {res = res.replace("\'", "")}); + if(escapeDoubleQuotes, {res = res.replace("\"", "")}); + res = res.replace("Rest", "\"Rest\""); + res = res.interpret; + }, { + //res.postln; + if(res.every({arg char; char.isDecDigit}), {res = res.asInteger}); + }); + }); + res +}; + +writeResources = {arg path; + var file, nameSpaces, modelItems, resString; + file = File(path,"w"); + + nameSpaces = [ + "music_data", "last_changes", + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + modelItems = [ + seq, lastXChanges, + curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize + ]; + + resString = [nameSpaces, modelItems].flop.collect({arg item; + var nameSpace, modelItem, depth = 0, insert = " "; + # nameSpace, modelItem = item; + if(nameSpace == "music_data", {depth = 3; insert = "\n"}); + if(nameSpace == "last_changes", {depth = 1; insert = "\n"}); + if(nameSpace == "order", {depth = 1; insert = "\n"}); + "\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem, depth) + }).join(",\n"); + + resString = "{\n" ++ resString ++ "\n}"; + + file.write(resString); + file.close; + resString +}; + +loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)}; + +loadModelJSON = {arg jsonObject; + var nameSpaces, data; + + //model = File(path, "r").readAllString.parseJSON; + + nameSpaces = [ + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + data = nameSpaces.collect({arg nS; msgInterpret.value(jsonObject[nS])}); + + //data.postln; + + # curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize = data; + + popSize = ranges.size; +}; + +loadLedgerFile = {arg path; + ledgerPath = path; + loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON) +}; + +loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]}; + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +//popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +//refUID = nil; +group = Group.new; +loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json"); +//passagesWeights = [1, 1, 1, 1, 1]; +//susWeights = [1, 1, 1]; + + +//------OSC funcs + +OSCdef(\load_ledger, {arg msg, time, addr, port; + loadLedgerFile.value(msg[1].asString); +}, \load_ledger); + +OSCdef(\load_model, {arg msg, time, addr, port; + loadModelFile.value(msg[1].asString); +}, \load_model); + + +OSCdef(\generate, {arg msg, time, addr, port; + var path, durSeeds, musPath, modelString; + msg.postln; + + path = msg[1].asString; + + loadModelFile.value(path); + + //refUID.postln; + + loadLedgerFile.value(ledgerPath); + if(ledger == nil, {ledger = ["tmp"]}); + if(ledger.last != "tmp", {ledger = ledger.add("tmp")}); + + lastXChanges = if(refUID == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln; + entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..2] ++ [entrancesProbVals[3..]] ++ [durSeeds[0]]); + passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..2] ++ [passagesProbVals[3..]] ++ [durSeeds[1]]); + exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..2] ++ [exitsProbVals[3..]] ++ [durSeeds[2]]); + + if(orders == nil, { + orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize); + //addr.sendMsg("/order", stringifyToDepth.value(orders, 1)); + }); + seq = seedFunc.value(genMotif, motifSeed).value; + + modelString = writeResources.value(path); + + //addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3)); + addr.sendMsg("/generated", path, modelString); +}, \generate); + + +OSCdef(\commit, {arg msg, time, addr, port; + var newLedger, modelPath, musString, musFile, test1, test2; + msg.postln; + + /* + test1 = msg[1].asString.parseJSON; + test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile; + msgInterpret.value(test1["music"])[0][0][0][1].class.postln; + msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln; + (test1["music"] == test2["music_data"]).postln; + */ + + curUID = genUID.value; + File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath); + File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath); + + modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; + writeResources.value(modelPath); + + File.delete(ledgerPath ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath, "w"); + ledger = ledger.drop(-1).add(curUID); + newLedger.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}"); + newLedger.close; + + addr.sendMsg("/committed", curUID, ledgerPath); + //refUID = curUID; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + // the cued sequence can now be read from file, so this can be cleaned up + var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; + pSeq = []; + cuedSeek = (seq != nil); + indexStart = msg[2].asInteger; + indexEnd = ledger.size - if(cuedSeek, {2}, {1}); + //ledger.postln; + if(((indexStart == (ledger.size - 1)) && cuedSeek).not, { + ledger[indexStart..indexEnd].do({arg uid, index; + var path, file; + path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath; + file = File(path, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, indexStart + index, uid]); + file.close; + }); + }); + if(cuedSeek, {pSeq = pSeq.add([seq, ledger.size - 1])}); + patterns = genPatterns.value(pSeq, addr); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; + +1223423434123.asHexString.toLower + +Date.getDate.rawSeconds +Date.seed.asHexString.toLower + +n = NetAddr("localhost", 8080); +n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals"); \ No newline at end of file diff --git a/resources/7aa8c429/7aa8c429_mus_model.json b/resources/7aa8c429/7aa8c429_mus_model.json new file mode 100644 index 0000000..35572e0 --- /dev/null +++ b/resources/7aa8c429/7aa8c429_mus_model.json @@ -0,0 +1,46 @@ +{ +"music_data": +[ + [ + [ + [ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 1 ], + [ [ [ "Rest" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0 ], + [ [ [ "Rest" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ] ], 0.75 ] + ], + [ + [ [ [ "Rest" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.875 ], + [ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.75 ], + [ [ [ 0, 1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 1, 0, 0, 0, -1 ], [ "Rest" ] ], 1 ], + [ [ [ "Rest" ], [ "Rest" ], [ 0, 1, 0, 0, 0, -1 ], [ "Rest" ] ], 0 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 0.625 ] + ] + ] +], +"last_changes": +[ + [ [ 0, 1, 0, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], + [ [ 0, 1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, -1, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], + [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], + [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ] ], + [ [ 0, 1, 0, 0, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 1, 0, 0, 0, -1 ], [ 1, 0, 0, 0, 0, -1 ] ] +], +"cur_uid": "7aa8c429", +"ref_uid": "4c01589b", +"order_seed": 367527, +"dur_seed": 393265, +"motifs_seed": 960266, +"entrances_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.5, 0.5, 1, 0.5 ], +"passages_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.5, 0.5, 1, 0.5 ], +"exits_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.5, 0.5, 1, 0.5 ], +"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ], +"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ], +"order": +[ + [ [ 2 ], [ 1, 3 ], [ 0 ] ], + [ [ 0 ], [ 2 ], [ 3, 1 ] ] +], +"sus_weights": [ 1, 0, 0 ], +"order_size": [ 1, 3 ], +"passages_size": [ 0, 2 ] +} \ No newline at end of file diff --git a/resources/7ac10d34/7ac10d34_code.scd b/resources/7ac10d34/7ac10d34_code.scd new file mode 100644 index 0000000..65c17df --- /dev/null +++ b/resources/7ac10d34/7ac10d34_code.scd @@ -0,0 +1,719 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck, +msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON; + +// model vars +//(model and global vars mostly set by OSC funcs +var curUID, refUID, orderSeed, durSeed, motifSeed, +entrancesProbVals, passagesProbVals, exitsProbVals, +ranges, orders, susWeights, passagesWeights, passagesSize, orderSize; + +// model aux vars +var entrancesDurFunc, passagesDurFunc, exitsDurFunc; + +// other global vars +var lastXChanges, popSize, exPath, dir, primes, dims, tuples, +seq, group, player, ledgerPath, ledger, currentlyPlayingUID; + + +// install JSON quark +if(Quarks.isInstalled("JSONlib").not, { + Quarks.install("https://github.com/musikinformatik/JSONlib.git"); + thisProcess.recompile; + //HelpBrowser.openHelpFor("Classes/JSONlib"); +}); + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genDurFunc = {arg chordProb, min, max, envData; + var env, pTable, durFunc; + env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + durFunc = {arg allowChord; + var res; + res = if(allowChord.not, { + pTable.tableRand * (max - min) + min + }, { + if(1.0.rand < chordProb, {0}, {pTable.tableRand * (max - min) + min}); + }).round(0.125); + if(res.asInteger == res, {res = res.asInteger}); + res + }; + seedFunc.value(durFunc, durSeed); +}; + +genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5; + ((maxMotifLength - minMotifLength).rand + minMotifLength).collect({ + var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order; + noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum); + noProgIns = (popSize - noSusIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] + }); +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = passagesWeights; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, flatOrder, res, isInChord, allowChord, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + flatOrder = silent ++ sus ++ prog; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + isInChord = popSize.collect({false}); + allowChord = false; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + flatOrder.do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + allowChord = if((sus ++ silent).includes(ins), { + (sus ++ silent).includes(ins) && (ins != sus.last); + }, { + if(i < (flatOrder.size - 1), {(isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not}, {false}); + }); + dur = passagesDurFunc.value(allowChord); + if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})}); + + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + + // pad ending + if(isLastOrder, { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + allowChord = (voices != popSize.collect({["Rest"]})); + dur = passagesDurFunc.value(allowChord); + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = { + var repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + + orders.do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~addr.sendMsg(~indexPath, ~indexMsg); + ~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3)); + //~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln); + }; +}); + +genPatterns = {arg inSeq, addr; + var voices, durs, patterns, res, indices, sectionDurs, ids, seq; + seq = inSeq.collect({arg mSeq; mSeq[0]}); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + indices = inSeq.collect({arg mSeq, m; mSeq[1]}); + ids = inSeq.collect({arg mSeq, m; mSeq[2]}); + sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum}); + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ) + }) ++ + [ + Pbind( + \type, \osc, + \addr, addr, + \indexPath, "/cur_play_index", + \indexMsg, Pseq(indices.postln, 1), + \seqPath, "/mus_seq", + \seqMsg, Pseq(seq, 1), + \dur, Pseq(sectionDurs, 1) + ); + ] + ); + res +}; + +/* +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; +*/ + + +//------resource management funcs + +genUID = {Date.seed.asHexString.toLower}; + +seedFunc = {arg func, seed; + var funcArgs, next; + next = Routine({loop{func.valueArray(funcArgs).yield }}); + next.randSeed_(seed); + {arg ...args; funcArgs = args; next.value} +}; + +stringifyToDepth = {arg data, maxDepth = 1; + var prettyString = "", rCount = 0, writeArray, indent; + + if(maxDepth == 0, { + data.asCompileString + }, { + indent = {arg size; size.collect({" "}).join("")}; + writeArray = {arg array; + prettyString = prettyString ++ indent.value(rCount) ++ "[\n"; + rCount = rCount + 1; + if(rCount < (maxDepth - 0), { + array.do({arg subArray; writeArray.value(subArray)}); + }, { + prettyString = prettyString ++ array.collect({arg subArray; + indent.value(rCount + 1) ++ subArray.asCompileString + }).join(",\n"); + }); + rCount = rCount - 1; + prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n"; + }; + + writeArray.value(data); + prettyString.replace(",\n\n", "\n").drop(-2); + }) +}; + +sanityCheck = {arg motif, index; + //print functions = very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true; + var res; + + res = in; + if(res.isNil.not, { + if((res.isArray && res.isString.not), { + res = res.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + if(escapeSingleQuotes, {res = res.replace("\'", "")}); + if(escapeDoubleQuotes, {res = res.replace("\"", "")}); + res = res.replace("Rest", "\"Rest\""); + res = res.interpret; + }, { + //res.postln; + if(res.every({arg char; char.isDecDigit}), {res = res.asInteger}); + }); + }); + res +}; + +writeResources = {arg path; + var file, nameSpaces, modelItems, resString; + file = File(path,"w"); + + nameSpaces = [ + "music_data", "last_changes", + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + modelItems = [ + seq, lastXChanges, + curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize + ]; + + resString = [nameSpaces, modelItems].flop.collect({arg item; + var nameSpace, modelItem, depth = 0, insert = " "; + # nameSpace, modelItem = item; + if(nameSpace == "music_data", {depth = 3; insert = "\n"}); + if(nameSpace == "last_changes", {depth = 1; insert = "\n"}); + if(nameSpace == "order", {depth = 1; insert = "\n"}); + "\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem.postln, depth).postln + }).join(",\n"); + + resString = "{\n" ++ resString ++ "\n}"; + + file.write(resString); + file.close; +}; + +loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)}; + +loadModelJSON = {arg model; + var nameSpaces, data; + + //model = File(path, "r").readAllString.parseJSON; + + nameSpaces = [ + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + data = nameSpaces.collect({arg nS; msgInterpret.value(model[nS]).postln}); + + data.postln; + + # curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize = data; + + popSize = ranges.size; +}; + +loadLedgerFile = {arg path; + ledgerPath = path; + loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON) +}; + +loadLedgerJSON = {arg ledger; ledger = ledger["ledger"]}; + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +//popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +//refUID = nil; +group = Group.new; +loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json"); +//passagesWeights = [1, 1, 1, 1, 1]; +//susWeights = [1, 1, 1]; + + +//------OSC funcs + +OSCdef(\load_ledger, {arg msg, time, addr, port; + loadLedgerFile.value(msg[1].asString); +}, \load_ledger); + +OSCdef(\load_model, {arg msg, time, addr, port; + loadModelFile.value(msg[1].asString); +}, \load_model); + + +OSCdef(\generate, {arg msg, time, addr, port; + var path, dFormat, condition, musPath; + msg.postln; + + path = msg[1].asString; + + loadModelFile.value(path); + + refUID.postln; + + loadLedgerFile.value(ledgerPath); + if(ledger == nil, {ledger = ["tmp"]}); + if(ledger.last != "tmp", {ledger = ledger.add("tmp")}); + + lastXChanges = if(refUID == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + refUID.postln; + file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..2] ++ [entrancesProbVals[3..]]); + passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..2] ++ [passagesProbVals[3..]]); + exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..2] ++ [exitsProbVals[3..]]); + + if(orders == nil, { + orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize); + addr.sendMsg("/order", stringifyToDepth.value(orders, 1)); + }); + seq = seedFunc.value(genMotif, motifSeed).value; + + //musPath = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath; + writeResources.value(path); + + //orders = nil; + //addr.sendMsg("/current_uid", curUID); + //addr.sendMsg("/ledger", prettifyArray.value(ledger, 1).replace("\"", "")); + //addr.sendMsg("/ledger_size", ledger.size); + //addr.sendMsg("/mus_seq", prettifyArray.value(seq, 3)); + addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3)); +}, \generate); + + +OSCdef(\commit, {arg msg, time, addr, port; + var newLedger, modelPath, musString, musFile, test1, test2; + msg.postln; + + /* + test1 = msg[1].asString.parseJSON; + test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile; + msgInterpret.value(test1["music"])[0][0][0][1].class.postln; + msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln; + (test1["music"] == test2["music_data"]).postln; + */ + + curUID = genUID.value; + File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath); + File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath); + + modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; + writeResources.value(modelPath); + + File.delete(ledgerPath.postln ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath.postln, "w"); + ledger = ledger.postln.drop(-1).add(curUID); + newLedger.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}"); + newLedger.close; + + addr.sendMsg("/committed", curUID, ledgerPath); + //refUID = curUID; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + // the cued sequence can now be read from file, so this can be cleaned up + var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; + pSeq = []; + cuedSeek = (seq != nil); + indexStart = msg[2].asInteger; + indexEnd = ledger.size - if(cuedSeek, {2}, {1}); + if(((indexStart == (ledger.size - 1)) && cuedSeek).not, { + ledger[indexStart..indexEnd].do({arg uid, index; + var file; + (indexStart + index).postln; + file = File((dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_music" ++ ".json").standardizePath, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), indexStart + index, uid]); + file.close; + }); + }); + if(cuedSeek, {pSeq = pSeq.add([seq, ledger.size - 1])}); + patterns = genPatterns.value(pSeq, addr); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; + +1223423434123.asHexString.toLower + +Date.getDate.rawSeconds +Date.seed.asHexString.toLower + +n = NetAddr("localhost", 8080); +n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals"); \ No newline at end of file diff --git a/resources/7ac10d34/7ac10d34_gui_state.json b/resources/7ac10d34/7ac10d34_gui_state.json new file mode 100644 index 0000000..84e6edd --- /dev/null +++ b/resources/7ac10d34/7ac10d34_gui_state.json @@ -0,0 +1,1359 @@ +{ + "motif_label": "motif", + "seeds_label": "seeds", + "order": "[\n [ [ 3, 1, 0 ], [ 2 ], [ ] ],\n [ [ 1, 2 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 3 ] ],\n [ [ 3, 2 ], [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], [ 0 ] ],\n [ [ 2, 3 ], [ 0, 1, 0 ], [ ] ]\n]", + "order_lock": 1, + "order_size": [ + 3, + 8 + ], + "order_size_v2": 8, + "order_size_v1": 3, + "order_size_panel": -1, + "passage_size_v2": 8, + "passage_size_v1": 2, + "passage_size_panel": -1, + "sus_weights": [ + null, + null, + null + ], + "range_matrix": [ + null, + null, + null, + null + ], + "instrumentation": [ + 0, + 0 + ], + "entrances_probs_sync": "passages", + "entrances": -1, + "passages_probs_sync": "passages", + "passages": -1, + "exits_probs_sync": "passages", + "exits": -1, + "dur_panel": 0, + "durations": -1, + "passages_weights": [ + null, + null, + null, + null, + null + ], + "weights": -1, + "seeds_tab_panel": 0, + "weights_seed_lock": 0, + "weights_seed": 534103, + "sus_weights/0_slider_val": 0.21, + "sus_weights/0_slider_slider": 0.21, + "sus_weights/0_slider_input": 0.21, + "sus_weights/0_slider_label": 1, + "sus_weights/0_slider": -1, + "sus_weights/1_slider_val": 0.35, + "sus_weights/1_slider_slider": 0.35, + "sus_weights/1_slider_input": 0.35, + "sus_weights/1_slider_label": 2, + "sus_weights/1_slider": -1, + "sus_weights/2_slider_val": 0.21, + "sus_weights/2_slider_slider": 0.21, + "sus_weights/2_slider_input": 0.21, + "sus_weights/2_slider_label": 3, + "sus_weights/2_slider": -1, + "passages_weights/0_slider_val": 0.49, + "passages_weights/0_slider_slider": 0.49, + "passages_weights/0_slider_input": 0.49, + "passages_weights/0_slider_label": "step", + "passages_weights/0_slider": -1, + "passages_weights/1_slider_val": 0.53, + "passages_weights/1_slider_slider": 0.53, + "passages_weights/1_slider_input": 0.53, + "passages_weights/1_slider_label": "dc", + "passages_weights/1_slider": -1, + "passages_weights/2_slider_val": 0.35, + "passages_weights/2_slider_slider": 0.35, + "passages_weights/2_slider_input": 0.35, + "passages_weights/2_slider_label": "range", + "passages_weights/2_slider": -1, + "passages_weights/3_slider_val": 0.59, + "passages_weights/3_slider_slider": 0.59, + "passages_weights/3_slider_input": 0.59, + "passages_weights/3_slider_label": "registration", + "passages_weights/3_slider": -1, + "passages_weights/4_slider_val": 0.39, + "passages_weights/4_slider_slider": 0.39, + "passages_weights/4_slider_input": 0.39, + "passages_weights/4_slider_label": "hd", + "passages_weights/4_slider": -1, + "range_matrix/0_val_input_min": -853.2067988668555, + "range_matrix/0_val_rslider": [ + -853.2067988668555, + 401 + ], + "range_matrix/0_val_input_max": 401, + "range_matrix/0_val": -1, + "range_matrix/1_val_input_min": -659, + "range_matrix/1_val_rslider": [ + -659, + 880 + ], + "range_matrix/1_val_input_max": 880, + "range_matrix/1_val": -1, + "range_matrix/2_val_input_min": -241, + "range_matrix/2_val_rslider": [ + -241, + 1869 + ], + "range_matrix/2_val_input_max": 1869, + "range_matrix/2_val": -1, + "range_matrix/3_val_input_min": -27, + "range_matrix/3_val_rslider": [ + -27, + 2063 + ], + "range_matrix/3_val_input_max": 2063, + "range_matrix/3_val": -1, + "entrances_probs_chord_slider_val": 0.66, + "entrances_probs_chord_slider_slider": 0.66, + "entrances_probs_chord_slider_input": 0.66, + "entrances_probs_chord_slider_label": "chord prob", + "entrances_probs_chord_slider": -1, + "entrances_probs_vals": [ + 0.63, + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.3963730569948187, + 0.8716216216216216, + 0.4948186528497409, + 0.5912162162162162, + 0.5362694300518135, + 0.8614864864864865, + 0.6424870466321243, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "entrances_probs": -1, + "passages_probs_chord_slider_val": 0.63, + "passages_probs_chord_slider_slider": 0.63, + "passages_probs_chord_slider_input": 0.63, + "passages_probs_chord_slider_label": "chord prob", + "passages_probs_chord_slider": -1, + "passages_probs_vals": [ + 0.63, + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.3963730569948187, + 0.8716216216216216, + 0.4948186528497409, + 0.5912162162162162, + 0.5362694300518135, + 0.8614864864864865, + 0.6424870466321243, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "passages_probs": -1, + "exits_probs_chord_slider_val": 0, + "exits_probs_chord_slider_slider": 0, + "exits_probs_chord_slider_input": 0, + "exits_probs_chord_slider_label": "chord prob", + "exits_probs_chord_slider": -1, + "exits_probs_vals": [ + 0, + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.4948186528497409, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "exits_probs": -1, + "step_env_env_vals": [ + 0, + 5, + 0, + 0, + 0, + 0, + 0.14609053497942387, + 0.7613636363636364, + 0.20164609053497942, + 0.26136363636363635, + 0.24279835390946503, + 0.7215909090909092, + 0.39094650205761317, + 0.875, + 0.4567901234567901, + 0.44318181818181823, + 0.5432098765432098, + 0.34659090909090906, + 0.6481481481481481, + 0.8011363636363636, + 0.6810699588477366, + 0.5170454545454546, + 0.8868312757201646, + 0.49431818181818177, + 0.8868312757201646, + 0.49431818181818177 + ], + "step_env_env_canvas": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0.14609053497942387, + 0.7613636363636364 + ], + [ + 0.20164609053497942, + 0.26136363636363635 + ], + [ + 0.24279835390946503, + 0.7215909090909092 + ], + [ + 0.39094650205761317, + 0.875 + ], + [ + 0.4567901234567901, + 0.44318181818181823 + ], + [ + 0.5432098765432098, + 0.34659090909090906 + ], + [ + 0.6481481481481481, + 0.8011363636363636 + ], + [ + 0.6810699588477366, + 0.5170454545454546 + ], + [ + 0.8868312757201646, + 0.49431818181818177 + ], + [ + 0.8868312757201646, + 0.49431818181818177 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "step_env_env_size": 12, + "step_env_env_flatten": 0, + "step_env_env_rslider": [ + 0, + 5 + ], + "step_env_env_rslider_v2": 5, + "step_env_env_rslider_v1": 0, + "step_env_env_mpos": "", + "step_env_env": -1, + "entrances_probs_dur_env_vals": [ + 0.515267175572519, + 4.599236641221374, + 0, + 0.5, + 0.2772020725388601, + 0.7972972972972973, + 0.45077720207253885, + 0.8783783783783784, + 0.5, + 0.5, + 0.727979274611399, + 0.45270270270270274, + 0.7357512953367875, + 0.6486486486486487, + 0.8911917098445595, + 0.7905405405405406, + 1, + 0.5 + ], + "entrances_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.2772020725388601, + 0.7972972972972973 + ], + [ + 0.45077720207253885, + 0.8783783783783784 + ], + [ + 0.5, + 0.5 + ], + [ + 0.727979274611399, + 0.45270270270270274 + ], + [ + 0.7357512953367875, + 0.6486486486486487 + ], + [ + 0.8911917098445595, + 0.7905405405405406 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "entrances_probs_dur_env_size": 8, + "entrances_probs_dur_env_flatten": 0, + "entrances_probs_dur_env_rslider": [ + 0.515267175572519, + 4.599236641221374 + ], + "entrances_probs_dur_env_rslider_v2": 4.599236641221374, + "entrances_probs_dur_env_rslider_v1": 0.515267175572519, + "entrances_probs_dur_env_mpos": "", + "entrances_probs_dur_env": -1, + "passages_probs_dur_env_vals": [ + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.3963730569948187, + 0.8716216216216216, + 0.4948186528497409, + 0.5912162162162162, + 0.5362694300518135, + 0.8614864864864865, + 0.6424870466321243, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "passages_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.23316062176165803, + 0.7094594594594594 + ], + [ + 0.3963730569948187, + 0.8716216216216216 + ], + [ + 0.4948186528497409, + 0.5912162162162162 + ], + [ + 0.5362694300518135, + 0.8614864864864865 + ], + [ + 0.6424870466321243, + 0.5912162162162162 + ], + [ + 0.7901554404145078, + 0.8277027027027027 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "passages_probs_dur_env_size": 8, + "passages_probs_dur_env_flatten": 0, + "passages_probs_dur_env_rslider": [ + 0, + 5 + ], + "passages_probs_dur_env_rslider_v2": 5, + "passages_probs_dur_env_rslider_v1": 0, + "passages_probs_dur_env_mpos": "", + "passages_probs_dur_env": -1, + "exits_probs_dur_env_vals": [ + 0, + 5, + 0, + 0.5, + 0.5, + 0.5, + 1, + 0.5 + ], + "exits_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.5, + 0.5 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "exits_probs_dur_env_size": 3, + "exits_probs_dur_env_flatten": 0, + "exits_probs_dur_env_rslider": [ + 0, + 5 + ], + "exits_probs_dur_env_rslider_v2": 5, + "exits_probs_dur_env_rslider_v1": 0, + "exits_probs_dur_env_mpos": "", + "exits_probs_dur_env": -1, + "mus_seq": [ + [ + [ + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + "Rest" + ], + [ + "Rest" + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + "Rest" + ] + ], + 1.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + 0, + 1, + -3, + 0, + 2, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.75 + ], + [ + [ + [ + 1, + 1, + -2, + -2, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.625 + ], + [ + [ + [ + 1, + 1, + -3, + -1, + 0, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.625 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ] + ], + [ + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -2, + 0, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.375 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 2, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -2, + -1, + 2, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 0, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.875 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1 + ] + ], + [ + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 2, + 0, + -3, + -1, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.625 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + "Rest" + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + "Rest" + ] + ], + 1.875 + ], + [ + [ + [ + "Rest" + ], + [ + "Rest" + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + "Rest" + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + "Rest" + ], + [ + "Rest" + ], + [ + "Rest" + ] + ], + 0.875 + ] + ] + ] + ], + "root": [ + 0.20743639921722112, + 0 + ], + "order_seed": 798574, + "dur_seed": 884869, + "passages_size": [ + 0, + 10 + ], + "dur_seed_lock": 1, + "order_seed_lock": 0, + "seeds_panel": -1, + "motif_panel": [ + 0, + 0 + ], + "ref_uid": "6f1a789f", + "cur_uid": "7ac10d34" +} \ No newline at end of file diff --git a/resources/7ac10d34/7ac10d34_mus_model.json b/resources/7ac10d34/7ac10d34_mus_model.json new file mode 100644 index 0000000..73f197b --- /dev/null +++ b/resources/7ac10d34/7ac10d34_mus_model.json @@ -0,0 +1,59 @@ +{ +"music_data": +[ + [ + [ + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 1.375 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 1 ], [ "Rest" ] ], 0.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 1, 0, 0, 0, 0 ], [ "Rest" ] ], 0.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 1, 0 ], [ "Rest" ] ], 0.75 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 1, 0, 0, 0, -1, 0 ], [ "Rest" ] ], 1.5 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ] ], 1.125 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ] ], 1.625 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 1, 0, 0, -1, 0, 0 ], [ "Rest" ] ], 1.625 ] + ], + [ + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ "Rest" ] ], 0 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.25 ], + [ [ [ 1, -1, 1, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.125 ], + [ [ [ 2, -2, 0, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1 ], + [ [ [ 0, 1, 0, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 0.5 ], + [ [ [ 1, 0, -1, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.625 ], + [ [ [ 2, -1, 0, -1, 0, -1 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 2 ], + [ [ [ 2, -1, 0, -2, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.75 ], + [ [ [ 1, -1, 1, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.5 ], + [ [ [ 2, -2, 0, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.25 ], + [ [ [ 2, -2, 0, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ "Rest" ] ], 0.875 ], + [ [ [ 2, -2, 0, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0 ], + [ [ [ 2, -2, 0, -1, 0, 0 ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 0 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 1.375 ] + ] + ] +], +"last_changes": +[ + [ [ 1, 0, -1, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], + [ [ 2, -1, 0, -1, 0, -1 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], + [ [ 2, -1, 0, -2, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], + [ [ 1, -1, 1, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], + [ [ 2, -2, 0, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ] +], +"cur_uid": "7ac10d34", +"ref_uid": "46b6952a", +"order_seed": 638872, +"dur_seed": 225879, +"motifs_seed": 992393, +"entrances_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ], +"passages_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"exits_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ], +"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ], +"order": +[ + [ [ 0 ], [ 2, 2, 2, 2, 2, 2, 2 ], [ 3, 1 ] ], + [ [ 1, 2, 3 ], [ 0, 0, 0, 0, 0, 0, 0, 0 ], [ ] ] +], +"sus_weights": [ 0.75, 0.69, 0.75 ], +"order_size": [ 2, 6 ], +"passages_size": [ 0, 10 ] +} \ No newline at end of file diff --git a/resources/7e170ef8/7e170ef8_code.scd b/resources/7e170ef8/7e170ef8_code.scd new file mode 100644 index 0000000..b11446a --- /dev/null +++ b/resources/7e170ef8/7e170ef8_code.scd @@ -0,0 +1,718 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck, +msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON; + +// model vars +//(model and global vars mostly set by OSC funcs +var curUID, refUID, orderSeed, durSeed, motifSeed, +entrancesProbVals, passagesProbVals, exitsProbVals, +ranges, orders, susWeights, passagesWeights, passagesSize, orderSize; + +// model aux vars +var entrancesDurFunc, passagesDurFunc, exitsDurFunc; + +// other global vars +var lastXChanges, popSize, exPath, dir, primes, dims, tuples, +seq, group, player, ledgerPath, ledger, currentlyPlayingUID; + + +// install JSON quark +if(Quarks.isInstalled("JSONlib").not, { + Quarks.install("https://github.com/musikinformatik/JSONlib.git"); + thisProcess.recompile; + //HelpBrowser.openHelpFor("Classes/JSONlib"); +}); + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genDurFunc = {arg chordProb, min, max, envData; + var env, pTable, durFunc; + env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + durFunc = {arg allowChord; + var res; + res = if(allowChord.not, { + pTable.tableRand * (max - min) + min + }, { + if(1.0.rand < chordProb, {0}, {pTable.tableRand * (max - min) + min}); + }).round(0.125); + if(res.asInteger == res, {res = res.asInteger}); + res + }; + seedFunc.value(durFunc, durSeed); +}; + +genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5; + ((maxMotifLength - minMotifLength).rand + minMotifLength).collect({ + var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order; + noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum); + noProgIns = (popSize - noSusIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] + }); +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = passagesWeights; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, flatOrder, res, isInChord, allowChord, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + flatOrder = silent ++ sus ++ prog; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + isInChord = popSize.collect({false}); + allowChord = false; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + flatOrder.do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + allowChord = if((sus ++ silent).includes(ins), { + (sus ++ silent).includes(ins) && (ins != sus.last); + }, { + if(i < (flatOrder.size - 1), {(isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not}, {false}); + }); + dur = passagesDurFunc.value(allowChord); + if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})}); + + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + + // pad ending + if(isLastOrder, { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + allowChord = (voices != popSize.collect({["Rest"]})); + dur = passagesDurFunc.value(allowChord); + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = { + var repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + + orders.do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~addr.sendMsg(~indexPath, ~indexMsg); + ~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3)); + //~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln); + }; +}); + +genPatterns = {arg inSeq, addr; + var voices, durs, patterns, res, indices, sectionDurs, ids, seq; + seq = inSeq.collect({arg mSeq; mSeq[0]}); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + indices = inSeq.collect({arg mSeq, m; mSeq[1]}); + ids = inSeq.collect({arg mSeq, m; mSeq[2]}); + sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum}); + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ) + }) ++ + [ + Pbind( + \type, \osc, + \addr, addr, + \indexPath, "/cur_play_index", + \indexMsg, Pseq(indices.postln, 1), + \seqPath, "/mus_seq", + \seqMsg, Pseq(seq, 1), + \dur, Pseq(sectionDurs, 1) + ); + ] + ); + res +}; + +/* +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; +*/ + + +//------resource management funcs + +genUID = {Date.seed.asHexString.toLower}; + +seedFunc = {arg func, seed; + var funcArgs, next; + next = Routine({loop{func.valueArray(funcArgs).yield }}); + next.randSeed_(seed); + {arg ...args; funcArgs = args; next.value} +}; + +stringifyToDepth = {arg data, maxDepth = 1; + var prettyString = "", rCount = 0, writeArray, indent; + + if(maxDepth == 0, { + data.asCompileString + }, { + indent = {arg size; size.collect({" "}).join("")}; + writeArray = {arg array; + prettyString = prettyString ++ indent.value(rCount) ++ "[\n"; + rCount = rCount + 1; + if(rCount < (maxDepth - 0), { + array.do({arg subArray; writeArray.value(subArray)}); + }, { + prettyString = prettyString ++ array.collect({arg subArray; + indent.value(rCount + 1) ++ subArray.asCompileString + }).join(",\n"); + }); + rCount = rCount - 1; + prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n"; + }; + + writeArray.value(data); + prettyString.replace(",\n\n", "\n").drop(-2); + }) +}; + +sanityCheck = {arg motif, index; + //print functions = very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true; + var res; + + res = in; + if(res.isNil.not, { + if((res.isArray && res.isString.not), { + res = res.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + if(escapeSingleQuotes, {res = res.replace("\'", "")}); + if(escapeDoubleQuotes, {res = res.replace("\"", "")}); + res = res.replace("Rest", "\"Rest\""); + res = res.interpret; + }, { + //res.postln; + if(res.every({arg char; char.isDecDigit}), {res = res.asInteger}); + }); + }); + res +}; + +writeResources = {arg path; + var file, nameSpaces, modelItems, resString; + file = File(path,"w"); + + nameSpaces = [ + "music_data", "last_changes", + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + modelItems = [ + seq, lastXChanges, + curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize + ]; + + resString = [nameSpaces, modelItems].flop.collect({arg item; + var nameSpace, modelItem, depth = 0, insert = " "; + # nameSpace, modelItem = item; + if(nameSpace == "music_data", {depth = 3; insert = "\n"}); + if(nameSpace == "last_changes", {depth = 1; insert = "\n"}); + if(nameSpace == "order", {depth = 1; insert = "\n"}); + "\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem.postln, depth).postln + }).join(",\n"); + + resString = "{\n" ++ resString ++ "\n}"; + + file.write(resString); + file.close; +}; + +loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)}; + +loadModelJSON = {arg model; + var nameSpaces, data; + + //model = File(path, "r").readAllString.parseJSON; + + nameSpaces = [ + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + data = nameSpaces.collect({arg nS; msgInterpret.value(model[nS]).postln}); + + data.postln; + + # curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize = data; + + popSize = ranges.size; +}; + +loadLedgerFile = {arg path; + ledgerPath = path; + loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON) +}; + +loadLedgerJSON = {arg ledger; ledger = ledger["ledger"]}; + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +//popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +//refUID = nil; +group = Group.new; +loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json"); +//passagesWeights = [1, 1, 1, 1, 1]; +//susWeights = [1, 1, 1]; + + +//------OSC funcs + +OSCdef(\load_ledger, {arg msg, time, addr, port; + loadLedgerFile.value(msg[1].asString); +}, \load_ledger); + +OSCdef(\load_model, {arg msg, time, addr, port; + loadModelFile.value(msg[1].asString); +}, \load_model); + + +OSCdef(\generate, {arg msg, time, addr, port; + var path, dFormat, condition, musPath; + msg.postln; + + path = msg[1].asString; + + loadModelFile.value(path); + + refUID.postln; + + loadLedgerFile.value(ledgerPath); + if(ledger.last != "tmp", {ledger = ledger.add("tmp")}); + + lastXChanges = if(refUID == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + refUID.postln; + file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..2] ++ [entrancesProbVals[3..]]); + passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..2] ++ [passagesProbVals[3..]]); + exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..2] ++ [exitsProbVals[3..]]); + + if(orders == nil, { + orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize); + addr.sendMsg("/order", stringifyToDepth.value(orders, 1)); + }); + seq = seedFunc.value(genMotif, motifSeed).value; + + //musPath = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath; + writeResources.value(path); + + //orders = nil; + //addr.sendMsg("/current_uid", curUID); + //addr.sendMsg("/ledger", prettifyArray.value(ledger, 1).replace("\"", "")); + //addr.sendMsg("/ledger_size", ledger.size); + //addr.sendMsg("/mus_seq", prettifyArray.value(seq, 3)); + addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3)); +}, \generate); + + +OSCdef(\commit, {arg msg, time, addr, port; + var newLedger, modelPath, musString, musFile, test1, test2; + msg.postln; + + /* + test1 = msg[1].asString.parseJSON; + test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile; + msgInterpret.value(test1["music"])[0][0][0][1].class.postln; + msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln; + (test1["music"] == test2["music_data"]).postln; + */ + + curUID = genUID.value; + File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath); + File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath); + + modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; + writeResources.value(modelPath); + + File.delete(ledgerPath.postln ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath.postln, "w"); + ledger = ledger.postln.drop(-1).add(curUID); + newLedger.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}"); + newLedger.close; + + addr.sendMsg("/committed", curUID, ledgerPath); + //refUID = curUID; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + // the cued sequence can now be read from file, so this can be cleaned up + var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; + pSeq = []; + cuedSeek = (seq != nil); + indexStart = msg[2].asInteger; + indexEnd = ledger.size - if(cuedSeek, {2}, {1}); + if(((indexStart == (ledger.size - 1)) && cuedSeek).not, { + ledger[indexStart..indexEnd].do({arg uid, index; + var file; + (indexStart + index).postln; + file = File((dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_music" ++ ".json").standardizePath, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), indexStart + index, uid]); + file.close; + }); + }); + if(cuedSeek, {pSeq = pSeq.add([seq, ledger.size - 1])}); + patterns = genPatterns.value(pSeq, addr); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; + +1223423434123.asHexString.toLower + +Date.getDate.rawSeconds +Date.seed.asHexString.toLower + +n = NetAddr("localhost", 8080); +n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals"); \ No newline at end of file diff --git a/resources/7e170ef8/7e170ef8_gui_state.json b/resources/7e170ef8/7e170ef8_gui_state.json new file mode 100644 index 0000000..704cf3a --- /dev/null +++ b/resources/7e170ef8/7e170ef8_gui_state.json @@ -0,0 +1,1359 @@ +{ + "motif_label": "motif", + "seeds_label": "seeds", + "order": "[\n [ [ 3, 1, 0 ], [ 2 ], [ ] ],\n [ [ 1, 2 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 3 ] ],\n [ [ 3, 2 ], [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], [ 0 ] ],\n [ [ 2, 3 ], [ 0, 1, 0 ], [ ] ]\n]", + "order_lock": 1, + "order_size": [ + 3, + 8 + ], + "order_size_v2": 8, + "order_size_v1": 3, + "order_size_panel": -1, + "passage_size_v2": 8, + "passage_size_v1": 2, + "passage_size_panel": -1, + "sus_weights": [ + null, + null, + null + ], + "range_matrix": [ + null, + null, + null, + null + ], + "instrumentation": [ + 0, + 0 + ], + "entrances_probs_sync": "passages", + "entrances": -1, + "passages_probs_sync": "passages", + "passages": -1, + "exits_probs_sync": "passages", + "exits": -1, + "dur_panel": 0, + "durations": -1, + "passages_weights": [ + null, + null, + null, + null, + null + ], + "weights": -1, + "seeds_tab_panel": 0, + "weights_seed_lock": 0, + "weights_seed": 534103, + "sus_weights/0_slider_val": 0.21, + "sus_weights/0_slider_slider": 0.21, + "sus_weights/0_slider_input": 0.21, + "sus_weights/0_slider_label": 1, + "sus_weights/0_slider": -1, + "sus_weights/1_slider_val": 0.35, + "sus_weights/1_slider_slider": 0.35, + "sus_weights/1_slider_input": 0.35, + "sus_weights/1_slider_label": 2, + "sus_weights/1_slider": -1, + "sus_weights/2_slider_val": 0.21, + "sus_weights/2_slider_slider": 0.21, + "sus_weights/2_slider_input": 0.21, + "sus_weights/2_slider_label": 3, + "sus_weights/2_slider": -1, + "passages_weights/0_slider_val": 0.49, + "passages_weights/0_slider_slider": 0.49, + "passages_weights/0_slider_input": 0.49, + "passages_weights/0_slider_label": "step", + "passages_weights/0_slider": -1, + "passages_weights/1_slider_val": 0.53, + "passages_weights/1_slider_slider": 0.53, + "passages_weights/1_slider_input": 0.53, + "passages_weights/1_slider_label": "dc", + "passages_weights/1_slider": -1, + "passages_weights/2_slider_val": 0.35, + "passages_weights/2_slider_slider": 0.35, + "passages_weights/2_slider_input": 0.35, + "passages_weights/2_slider_label": "range", + "passages_weights/2_slider": -1, + "passages_weights/3_slider_val": 0.59, + "passages_weights/3_slider_slider": 0.59, + "passages_weights/3_slider_input": 0.59, + "passages_weights/3_slider_label": "registration", + "passages_weights/3_slider": -1, + "passages_weights/4_slider_val": 0.39, + "passages_weights/4_slider_slider": 0.39, + "passages_weights/4_slider_input": 0.39, + "passages_weights/4_slider_label": "hd", + "passages_weights/4_slider": -1, + "range_matrix/0_val_input_min": -853.2067988668555, + "range_matrix/0_val_rslider": [ + -853.2067988668555, + 401 + ], + "range_matrix/0_val_input_max": 401, + "range_matrix/0_val": -1, + "range_matrix/1_val_input_min": -659, + "range_matrix/1_val_rslider": [ + -659, + 880 + ], + "range_matrix/1_val_input_max": 880, + "range_matrix/1_val": -1, + "range_matrix/2_val_input_min": -241, + "range_matrix/2_val_rslider": [ + -241, + 1869 + ], + "range_matrix/2_val_input_max": 1869, + "range_matrix/2_val": -1, + "range_matrix/3_val_input_min": -27, + "range_matrix/3_val_rslider": [ + -27, + 2063 + ], + "range_matrix/3_val_input_max": 2063, + "range_matrix/3_val": -1, + "entrances_probs_chord_slider_val": 0.66, + "entrances_probs_chord_slider_slider": 0.66, + "entrances_probs_chord_slider_input": 0.66, + "entrances_probs_chord_slider_label": "chord prob", + "entrances_probs_chord_slider": -1, + "entrances_probs_vals": [ + 0.63, + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.3963730569948187, + 0.8716216216216216, + 0.4948186528497409, + 0.5912162162162162, + 0.5362694300518135, + 0.8614864864864865, + 0.6424870466321243, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "entrances_probs": -1, + "passages_probs_chord_slider_val": 0.63, + "passages_probs_chord_slider_slider": 0.63, + "passages_probs_chord_slider_input": 0.63, + "passages_probs_chord_slider_label": "chord prob", + "passages_probs_chord_slider": -1, + "passages_probs_vals": [ + 0.63, + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.3963730569948187, + 0.8716216216216216, + 0.4948186528497409, + 0.5912162162162162, + 0.5362694300518135, + 0.8614864864864865, + 0.6424870466321243, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "passages_probs": -1, + "exits_probs_chord_slider_val": 0, + "exits_probs_chord_slider_slider": 0, + "exits_probs_chord_slider_input": 0, + "exits_probs_chord_slider_label": "chord prob", + "exits_probs_chord_slider": -1, + "exits_probs_vals": [ + 0, + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.4948186528497409, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "exits_probs": -1, + "step_env_env_vals": [ + 0, + 5, + 0, + 0, + 0, + 0, + 0.14609053497942387, + 0.7613636363636364, + 0.20164609053497942, + 0.26136363636363635, + 0.24279835390946503, + 0.7215909090909092, + 0.39094650205761317, + 0.875, + 0.4567901234567901, + 0.44318181818181823, + 0.5432098765432098, + 0.34659090909090906, + 0.6481481481481481, + 0.8011363636363636, + 0.6810699588477366, + 0.5170454545454546, + 0.8868312757201646, + 0.49431818181818177, + 0.8868312757201646, + 0.49431818181818177 + ], + "step_env_env_canvas": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0.14609053497942387, + 0.7613636363636364 + ], + [ + 0.20164609053497942, + 0.26136363636363635 + ], + [ + 0.24279835390946503, + 0.7215909090909092 + ], + [ + 0.39094650205761317, + 0.875 + ], + [ + 0.4567901234567901, + 0.44318181818181823 + ], + [ + 0.5432098765432098, + 0.34659090909090906 + ], + [ + 0.6481481481481481, + 0.8011363636363636 + ], + [ + 0.6810699588477366, + 0.5170454545454546 + ], + [ + 0.8868312757201646, + 0.49431818181818177 + ], + [ + 0.8868312757201646, + 0.49431818181818177 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "step_env_env_size": 12, + "step_env_env_flatten": 0, + "step_env_env_rslider": [ + 0, + 5 + ], + "step_env_env_rslider_v2": 5, + "step_env_env_rslider_v1": 0, + "step_env_env_mpos": "", + "step_env_env": -1, + "entrances_probs_dur_env_vals": [ + 0.515267175572519, + 4.599236641221374, + 0, + 0.5, + 0.2772020725388601, + 0.7972972972972973, + 0.45077720207253885, + 0.8783783783783784, + 0.5, + 0.5, + 0.727979274611399, + 0.45270270270270274, + 0.7357512953367875, + 0.6486486486486487, + 0.8911917098445595, + 0.7905405405405406, + 1, + 0.5 + ], + "entrances_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.2772020725388601, + 0.7972972972972973 + ], + [ + 0.45077720207253885, + 0.8783783783783784 + ], + [ + 0.5, + 0.5 + ], + [ + 0.727979274611399, + 0.45270270270270274 + ], + [ + 0.7357512953367875, + 0.6486486486486487 + ], + [ + 0.8911917098445595, + 0.7905405405405406 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "entrances_probs_dur_env_size": 8, + "entrances_probs_dur_env_flatten": 0, + "entrances_probs_dur_env_rslider": [ + 0.515267175572519, + 4.599236641221374 + ], + "entrances_probs_dur_env_rslider_v2": 4.599236641221374, + "entrances_probs_dur_env_rslider_v1": 0.515267175572519, + "entrances_probs_dur_env_mpos": "", + "entrances_probs_dur_env": -1, + "passages_probs_dur_env_vals": [ + 0, + 5, + 0, + 0.5, + 0.23316062176165803, + 0.7094594594594594, + 0.3963730569948187, + 0.8716216216216216, + 0.4948186528497409, + 0.5912162162162162, + 0.5362694300518135, + 0.8614864864864865, + 0.6424870466321243, + 0.5912162162162162, + 0.7901554404145078, + 0.8277027027027027, + 1, + 0.5 + ], + "passages_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.23316062176165803, + 0.7094594594594594 + ], + [ + 0.3963730569948187, + 0.8716216216216216 + ], + [ + 0.4948186528497409, + 0.5912162162162162 + ], + [ + 0.5362694300518135, + 0.8614864864864865 + ], + [ + 0.6424870466321243, + 0.5912162162162162 + ], + [ + 0.7901554404145078, + 0.8277027027027027 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "passages_probs_dur_env_size": 8, + "passages_probs_dur_env_flatten": 0, + "passages_probs_dur_env_rslider": [ + 0, + 5 + ], + "passages_probs_dur_env_rslider_v2": 5, + "passages_probs_dur_env_rslider_v1": 0, + "passages_probs_dur_env_mpos": "", + "passages_probs_dur_env": -1, + "exits_probs_dur_env_vals": [ + 0, + 5, + 0, + 0.5, + 0.5, + 0.5, + 1, + 0.5 + ], + "exits_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.5, + 0.5 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "exits_probs_dur_env_size": 3, + "exits_probs_dur_env_flatten": 0, + "exits_probs_dur_env_rslider": [ + 0, + 5 + ], + "exits_probs_dur_env_rslider_v2": 5, + "exits_probs_dur_env_rslider_v1": 0, + "exits_probs_dur_env_mpos": "", + "exits_probs_dur_env": -1, + "mus_seq": [ + [ + [ + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + "Rest" + ], + [ + "Rest" + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + "Rest" + ] + ], + 1.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + 0, + 1, + -3, + 0, + 2, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.75 + ], + [ + [ + [ + 1, + 1, + -2, + -2, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.625 + ], + [ + [ + [ + 1, + 1, + -3, + -1, + 0, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.625 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ] + ], + [ + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -3, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -2, + 0, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.375 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 2, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -2, + -1, + 2, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 0, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.875 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1 + ] + ], + [ + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 0 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 2, + 0, + -3, + -1, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.625 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + 1, + 1, + -2, + -1, + 0, + 0 + ] + ], + 1.75 + ], + [ + [ + [ + 1, + 0, + -3, + 0, + 1, + -1 + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + "Rest" + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + 1, + 1, + -2, + -1, + 1, + 0 + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + "Rest" + ] + ], + 1.875 + ], + [ + [ + [ + "Rest" + ], + [ + "Rest" + ], + [ + 0, + 1, + -1, + -1, + 1, + 0 + ], + [ + "Rest" + ] + ], + 0 + ], + [ + [ + [ + "Rest" + ], + [ + "Rest" + ], + [ + "Rest" + ], + [ + "Rest" + ] + ], + 0.875 + ] + ] + ] + ], + "root": [ + 0.20743639921722112, + 0 + ], + "order_seed": 798574, + "dur_seed": 884869, + "passages_size": [ + 0, + 10 + ], + "dur_seed_lock": 1, + "order_seed_lock": 0, + "seeds_panel": -1, + "motif_panel": [ + 0, + 0 + ], + "ref_uid": "6f1a789f", + "cur_uid": "7e170ef8" +} \ No newline at end of file diff --git a/resources/7e170ef8/7e170ef8_mus_model.json b/resources/7e170ef8/7e170ef8_mus_model.json new file mode 100644 index 0000000..c9b8807 --- /dev/null +++ b/resources/7e170ef8/7e170ef8_mus_model.json @@ -0,0 +1,79 @@ +{ +"music_data": +[ + [ + [ + [ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 1.75 ], + [ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ] ], 0 ], + [ [ [ "Rest" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ] ], 0.625 ], + [ [ [ "Rest" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ] ], 0.875 ], + [ [ [ "Rest" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ] ], 1.375 ], + [ [ [ "Rest" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ] ], 0 ], + [ [ [ "Rest" ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ] ], 0.5 ], + [ [ [ "Rest" ], [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ] ], 0 ], + [ [ [ "Rest" ], [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0 ] ], 1.25 ], + [ [ [ "Rest" ], [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ] ], 0 ], + [ [ [ "Rest" ], [ 0, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ] ], 1.875 ] + ], + [ + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ] ], 1.625 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ] ], 0 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ] ], 0 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ] ], 1.75 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 1, 0, 0, 0, -1, 0 ] ], 1.75 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ -1, 0, 0, 0, 0, 1 ], [ 1, 0, 0, -1, 0, 0 ], [ 1, 0, 0, 0, -1, 0 ] ], 0 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ -1, 0, 0, 0, 0, 1 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ] ], 1.75 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, -1, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ] ], 1.875 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, -1, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ] ], 1.375 ] + ], + [ + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 1, 0, -1, 0, 0, 0 ] ], 1.375 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ "Rest" ], [ 1, 0, -1, 0, 0, 0 ] ], 1 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, -1, -1, 0, 0 ], [ "Rest" ], [ 1, 0, -1, 0, 0, 0 ] ], 1.125 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, -1, 0, 1, 0 ], [ "Rest" ], [ 1, 0, -1, 0, 0, 0 ] ], 1.625 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, -1, 0, 0, 0 ], [ "Rest" ], [ 1, 0, -1, 0, 0, 0 ] ], 1.75 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ], [ 1, 0, -1, 0, 0, 0 ] ], 1.125 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ], [ 1, 0, -1, 0, 0, 0 ] ], 1.25 ] + ], + [ + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ] ], 0 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 1, 0, 0 ] ], 1.25 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 1, 0, 0, 0, 0, 0 ] ], 1.25 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 1, -1, 0, 0, 0, 1 ] ], 1.5 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.25 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ "Rest" ] ], 0 ], + [ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0 ], + [ [ [ "Rest" ], [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 1 ] + ] + ] +], +"last_changes": +[ + [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ] ], + [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 1, 0, 0 ] ], + [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 1, 0, 0, 0, 0, 0 ] ], + [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 1, -1, 0, 0, 0, 1 ] ], + [ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ] +], +"cur_uid": "7e170ef8", +"ref_uid": "nil", +"order_seed": 142640, +"dur_seed": 629022, +"motifs_seed": 973728, +"entrances_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ], +"passages_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"exits_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ], +"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ], +"order": +[ + [ [ 2 ], [ 3, 1, 3, 3, 3, 1, 1, 3, 3, 1 ], [ 0 ] ], + [ [ 0 ], [ 1, 2, 3, 3, 1, 3, 1, 3 ], [ ] ], + [ [ 0, 3 ], [ 1, 1, 1, 1, 1, 1 ], [ 2 ] ], + [ [ 1, 2, 0 ], [ 3, 3, 3, 3 ], [ ] ] +], +"sus_weights": [ 0.75, 0.69, 0.75 ], +"order_size": [ 2, 6 ], +"passages_size": [ 0, 10 ] +} \ No newline at end of file diff --git a/resources/7ead41c3/7ead41c3_code.scd b/resources/7ead41c3/7ead41c3_code.scd new file mode 100644 index 0000000..b6ff291 --- /dev/null +++ b/resources/7ead41c3/7ead41c3_code.scd @@ -0,0 +1,734 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck, +msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON; + +// model vars +//(model and global vars mostly set by OSC funcs +var curUID, refUID, orderSeed, durSeed, motifSeed, +entrancesProbVals, passagesProbVals, exitsProbVals, +ranges, orders, susWeights, passagesWeights, passagesSize, orderSize; + +// model aux vars +var entrancesDurFunc, passagesDurFunc, exitsDurFunc; + +// other global vars +var lastXChanges, popSize, exPath, dir, primes, dims, tuples, +seq, group, player, ledgerPath, ledger, currentlyPlayingUID; + + +// install JSON quark +if(Quarks.isInstalled("JSONlib").not, { + Quarks.install("https://github.com/musikinformatik/JSONlib.git"); + thisProcess.recompile; + //HelpBrowser.openHelpFor("Classes/JSONlib"); +}); + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genDurFunc = {arg chordProb, min, max, envData, seed; + var env, pTable, durFunc; + env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + durFunc = {arg allowChord; + var res; + res = if(allowChord.not, { + pTable.tableRand * (max - min) + min + }, { + if(1.0.rand < chordProb, {0}, {pTable.tableRand * (max - min) + min}); + }).round(0.125); + if(res.asInteger == res, {res = res.asInteger}); + res + }; + seedFunc.value(durFunc, seed); +}; + +genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5; + ((maxMotifLength - minMotifLength).rand + minMotifLength).collect({ + var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order; + noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum); + noProgIns = (popSize - noSusIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] + }); +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = passagesWeights; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, flatOrder, res, isInChord, allowChord, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + flatOrder = silent ++ sus ++ prog; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + isInChord = popSize.collect({false}); + allowChord = false; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + flatOrder.do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + + allowChord = if((sus ++ silent).includes(ins), { + //(sus ++ silent).includes(ins) && (ins != sus.last); + ins != sus.last; + }, { + if(i < (flatOrder.size - 1), {(isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not}, {false}); + }); + if((orderIndex == 0) && sus.includes(ins), { + dur = entrancesDurFunc.value(allowChord); + }, { + dur = passagesDurFunc.value(allowChord); + }); + //dur = passagesDurFunc.value(allowChord); + if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})}); + + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + + // pad ending + if(orderIndex == (orders.size - 1), { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + allowChord = (voices != popSize.collect({["Rest"]})); + dur = exitsDurFunc.value(allowChord); + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = { + var repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + + orders.do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +/* +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~addr.sendMsg(~indexPath, ~indexMsg); + ~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3)); + //~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln); + }; +}); +*/ + +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~msg.postln; + ~addr.sendMsg(~path, *~msg); + }; +}); + +genPatterns = {arg inSeq, addr; + var voices, durs, patterns, res, indices, sectionDurs, msg, ids, seq; + seq = inSeq.collect({arg mSeq; mSeq[0]}); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + msg = inSeq.collect({arg mSeq, m; mSeq[1..]}); + //ids = inSeq.collect({arg mSeq, m; mSeq[2]}); + sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum}); + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ) + }) ++ + [ + Pbind( + \type, \osc, + \addr, addr, + //\indexPath, "/cur_play_index", + //\indexMsg, Pseq(indices, 1), + //\seqPath, "/mus_seq", + //\seqMsg, Pseq(seq, 1), + \path, "/playing", + \msg, Pseq(msg, 1), + \dur, Pseq(sectionDurs, 1) + ); + ] + ); + res +}; + +/* +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; +*/ + + +//------resource management funcs + +genUID = {Date.seed.asHexString.toLower}; + +seedFunc = {arg func, seed; + var funcArgs, next; + next = Routine({loop{func.valueArray(funcArgs).yield }}); + next.randSeed_(seed); + {arg ...args; funcArgs = args; next.value} +}; + +stringifyToDepth = {arg data, maxDepth = 1; + var prettyString = "", rCount = 0, writeArray, indent; + + if(maxDepth == 0, { + data.asCompileString + }, { + indent = {arg size; size.collect({" "}).join("")}; + writeArray = {arg array; + prettyString = prettyString ++ indent.value(rCount) ++ "[\n"; + rCount = rCount + 1; + if(rCount < maxDepth, { + array.do({arg subArray; writeArray.value(subArray)}); + }, { + prettyString = prettyString ++ array.collect({arg subArray; + indent.value(rCount + 1) ++ subArray.asCompileString + }).join(",\n"); + }); + rCount = rCount - 1; + prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n"; + }; + + writeArray.value(data); + prettyString.replace(",\n\n", "\n").drop(-2); + }) +}; + +sanityCheck = {arg motif, index; + //print functions = very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true; + var res; + + res = in; + if(res.isNil.not, { + if((res.isArray && res.isString.not), { + res = res.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + if(escapeSingleQuotes, {res = res.replace("\'", "")}); + if(escapeDoubleQuotes, {res = res.replace("\"", "")}); + res = res.replace("Rest", "\"Rest\""); + res = res.interpret; + }, { + //res.postln; + if(res.every({arg char; char.isDecDigit}), {res = res.asInteger}); + }); + }); + res +}; + +writeResources = {arg path; + var file, nameSpaces, modelItems, resString; + file = File(path,"w"); + + nameSpaces = [ + "music_data", "last_changes", + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + modelItems = [ + seq, lastXChanges, + curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize + ]; + + resString = [nameSpaces, modelItems].flop.collect({arg item; + var nameSpace, modelItem, depth = 0, insert = " "; + # nameSpace, modelItem = item; + if(nameSpace == "music_data", {depth = 3; insert = "\n"}); + if(nameSpace == "last_changes", {depth = 1; insert = "\n"}); + if(nameSpace == "order", {depth = 1; insert = "\n"}); + "\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem, depth) + }).join(",\n"); + + resString = "{\n" ++ resString ++ "\n}"; + + file.write(resString); + file.close; + resString +}; + +loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)}; + +loadModelJSON = {arg jsonObject; + var nameSpaces, data; + + //model = File(path, "r").readAllString.parseJSON; + + nameSpaces = [ + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + data = nameSpaces.collect({arg nS; msgInterpret.value(jsonObject[nS])}); + + //data.postln; + + # curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize = data; + + popSize = ranges.size; +}; + +loadLedgerFile = {arg path; + ledgerPath = path; + loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON) +}; + +loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]}; + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +//popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +//refUID = nil; +group = Group.new; +loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json"); +//passagesWeights = [1, 1, 1, 1, 1]; +//susWeights = [1, 1, 1]; + + +//------OSC funcs + +OSCdef(\load_ledger, {arg msg, time, addr, port; + loadLedgerFile.value(msg[1].asString); +}, \load_ledger); + +OSCdef(\load_model, {arg msg, time, addr, port; + loadModelFile.value(msg[1].asString); +}, \load_model); + + +OSCdef(\generate, {arg msg, time, addr, port; + var path, durSeeds, musPath, modelString; + msg.postln; + + path = msg[1].asString; + + loadModelFile.value(path); + + //refUID.postln; + + loadLedgerFile.value(ledgerPath); + if(ledger == nil, {ledger = ["tmp"]}); + if(ledger.last != "tmp", {ledger = ledger.add("tmp")}); + + lastXChanges = if(refUID == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln; + entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..2] ++ [entrancesProbVals[3..]] ++ [durSeeds[0]]); + passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..2] ++ [passagesProbVals[3..]] ++ [durSeeds[1]]); + exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..2] ++ [exitsProbVals[3..]] ++ [durSeeds[2]]); + + if(orders == nil, { + orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize); + //addr.sendMsg("/order", stringifyToDepth.value(orders, 1)); + }); + seq = seedFunc.value(genMotif, motifSeed).value; + + modelString = writeResources.value(path); + + //addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3)); + addr.sendMsg("/generated", path, modelString); +}, \generate); + + +OSCdef(\commit, {arg msg, time, addr, port; + var newLedger, modelPath, musString, musFile, test1, test2; + msg.postln; + + /* + test1 = msg[1].asString.parseJSON; + test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile; + msgInterpret.value(test1["music"])[0][0][0][1].class.postln; + msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln; + (test1["music"] == test2["music_data"]).postln; + */ + + curUID = genUID.value; + File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath); + File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath); + + modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; + writeResources.value(modelPath); + + File.delete(ledgerPath ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath, "w"); + ledger = ledger.drop(-1).add(curUID); + newLedger.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}"); + newLedger.close; + + addr.sendMsg("/committed", curUID, ledgerPath); + //refUID = curUID; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + // the cued sequence can now be read from file, so this can be cleaned up + var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; + pSeq = []; + cuedSeek = (seq != nil); + indexStart = msg[2].asInteger; + indexEnd = ledger.size - if(cuedSeek, {2}, {1}); + //ledger.postln; + if(((indexStart == (ledger.size - 1)) && cuedSeek).not, { + ledger[indexStart..indexEnd].do({arg uid, index; + var path, file; + path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath; + file = File(path, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, indexStart + index, uid]); + file.close; + }); + }); + if(cuedSeek, {pSeq = pSeq.add([seq, ledger.size - 1])}); + patterns = genPatterns.value(pSeq, addr); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; + +1223423434123.asHexString.toLower + +Date.getDate.rawSeconds +Date.seed.asHexString.toLower + +n = NetAddr("localhost", 8080); +n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals"); \ No newline at end of file diff --git a/resources/7ead41c3/7ead41c3_mus_model.json b/resources/7ead41c3/7ead41c3_mus_model.json new file mode 100644 index 0000000..9528437 --- /dev/null +++ b/resources/7ead41c3/7ead41c3_mus_model.json @@ -0,0 +1,77 @@ +{ +"music_data": +[ + [ + [ + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ 2, 0, 0, -1, 0, 0 ] ], 0 ], + [ [ [ "Rest" ], [ 2, -1, 0, -1, 0, 0 ], [ "Rest" ], [ 2, 0, 0, -1, 0, 0 ] ], 0.625 ], + [ [ [ "Rest" ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.875 ], + [ [ [ 0, -1, 2, 0, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 0.75 ], + [ [ [ 2, -2, 0, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 0.75 ], + [ [ [ 2, -1, 0, -1, -1, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.125 ], + [ [ [ 1, -1, 0, -1, 0, 1 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.75 ], + [ [ [ 1, -2, 1, 0, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 0.5 ], + [ [ [ 1, 0, 0, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.5 ], + [ [ [ 2, -1, -1, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.125 ], + [ [ [ 0, 0, 1, 0, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.625 ], + [ [ [ 0, -1, 1, 0, 1, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.75 ], + [ [ [ 1, -1, 0, -1, 0, 1 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 1.625 ] + ], + [ + [ [ [ 1, -1, 0, -1, 0, 1 ], [ 2, -1, 0, -1, 0, 0 ], [ "Rest" ], [ 2, 0, 0, -1, 0, 0 ] ], 0 ], + [ [ [ 1, -1, 0, -1, 0, 1 ], [ 2, -1, 0, -1, 0, 0 ], [ "Rest" ], [ 2, -1, 0, -1, 0, 1 ] ], 0 ], + [ [ [ 1, -1, 0, -1, 0, 1 ], [ 2, -2, 0, -1, 0, 1 ], [ "Rest" ], [ 2, -1, 0, -1, 0, 1 ] ], 1.125 ], + [ [ [ 1, -1, 0, -1, 0, 1 ], [ 2, -2, 0, -1, 0, 1 ], [ "Rest" ], [ 1, -1, 0, 0, 0, 1 ] ], 0.875 ], + [ [ [ 1, -1, 0, -1, 0, 1 ], [ 1, -1, 1, -1, 0, 1 ], [ "Rest" ], [ 1, -1, 0, 0, 0, 1 ] ], 0 ], + [ [ [ 1, -1, 0, -1, 0, 1 ], [ 1, -1, 1, -1, 0, 1 ], [ "Rest" ], [ 1, -1, 0, -1, 0, 2 ] ], 0.75 ], + [ [ [ 1, -1, 0, -1, 0, 1 ], [ 2, -1, 0, -2, 0, 1 ], [ "Rest" ], [ 1, -1, 0, -1, 0, 2 ] ], 1.25 ], + [ [ [ 1, -1, 0, -1, 0, 1 ], [ 2, -1, 0, -1, 0, 0 ], [ "Rest" ], [ 1, -1, 0, -1, 0, 2 ] ], 1.75 ] + ], + [ + [ [ [ 1, -1, 0, -1, 0, 1 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], 1.625 ], + [ [ [ 0, 0, 1, 0, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], 0 ], + [ [ [ 0, 0, 1, 0, 0, 0 ], [ 0, -1, 1, 0, 0, 1 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], 0.625 ], + [ [ [ 0, -1, 1, -1, 0, 2 ], [ 0, -1, 1, 0, 0, 1 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], 0.625 ], + [ [ [ 0, -1, 1, 0, 1, 0 ], [ 0, -1, 1, 0, 0, 1 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], 0 ], + [ [ [ 0, -1, 1, 0, 1, 0 ], [ 0, 0, 1, 0, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], 1.5 ], + [ [ [ 0, -1, 1, 0, 1, 0 ], [ 1, -2, 1, 0, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], 0.75 ], + [ [ [ 1, -1, 1, 0, -1, 0 ], [ 1, -2, 1, 0, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], 1.25 ], + [ [ [ 1, -1, 1, 0, -1, 0 ], [ -1, -1, 0, 0, 0, 2 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], 1.75 ], + [ [ [ 1, -1, 0, -1, 0, 1 ], [ -1, -1, 0, 0, 0, 2 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], 0 ], + [ [ [ 1, -1, 0, -1, 0, 1 ], [ 0, -1, -1, -1, 0, 2 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], 0.75 ], + [ [ [ 1, -1, 0, -1, 0, 1 ], [ -1, 0, 0, -1, 0, 2 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], 1.25 ], + [ [ [ 1, -1, 0, -1, 0, 1 ], [ -1, 0, 0, -1, 0, 2 ], [ "Rest" ], [ 1, -1, 0, -1, 0, 2 ] ], 0 ], + [ [ [ 1, -1, 0, -1, 0, 1 ], [ "Rest" ], [ "Rest" ], [ 1, -1, 0, -1, 0, 2 ] ], 0.75 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ 1, -1, 0, -1, 0, 2 ] ], 0 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 1.875 ] + ] + ] +], +"last_changes": +[ + [ [ 1, -1, 1, 0, -1, 0 ], [ 1, -2, 1, 0, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], + [ [ 1, -1, 1, 0, -1, 0 ], [ -1, -1, 0, 0, 0, 2 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], + [ [ 1, -1, 0, -1, 0, 1 ], [ -1, -1, 0, 0, 0, 2 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], + [ [ 1, -1, 0, -1, 0, 1 ], [ 0, -1, -1, -1, 0, 2 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ], + [ [ 1, -1, 0, -1, 0, 1 ], [ -1, 0, 0, -1, 0, 2 ], [ 1, -1, 1, 0, 0, 0 ], [ 1, -1, 0, -1, 0, 2 ] ] +], +"cur_uid": "7ead41c3", +"ref_uid": "46b6952a", +"order_seed": 941210, +"dur_seed": 186474, +"motifs_seed": 450931, +"entrances_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ], +"passages_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"exits_probs_vals": [ 0.75, 0.5, 2, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], +"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ], +"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ], +"order": +[ + [ [ 3, 1, 2 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ ] ], + [ [ 0 ], [ 3, 1, 3, 1, 3, 1, 1 ], [ 2 ] ], + [ [ 2, 3 ], [ 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1 ], [ ] ] +], +"sus_weights": [ 0.75, 0.69, 0.75 ], +"order_size": [ 2, 6 ], +"passages_size": [ 0, 10 ] +} \ No newline at end of file diff --git a/resources/piece_ledger.json b/resources/piece_ledger.json new file mode 100644 index 0000000..7fa31dc --- /dev/null +++ b/resources/piece_ledger.json @@ -0,0 +1,17 @@ +{ +"ledger": +[ + "4c01589b", + "7e170ef8", + "46b6952a", + "7ac10d34", + "640eeed3", + "5e947063", + "5cf1e9ab", + "7aa8c429", + "7ead41c3", + "62b894e8", + "628d5c8b", + "55930f4d" +] +} \ No newline at end of file diff --git a/resources/piece_ledger.json_bak b/resources/piece_ledger.json_bak new file mode 100644 index 0000000..2e489ab --- /dev/null +++ b/resources/piece_ledger.json_bak @@ -0,0 +1,16 @@ +{ +"ledger": +[ + "4c01589b", + "7e170ef8", + "46b6952a", + "7ac10d34", + "640eeed3", + "5e947063", + "5cf1e9ab", + "7aa8c429", + "7ead41c3", + "62b894e8", + "628d5c8b" +] +} \ No newline at end of file diff --git a/resources/piece_ledger.json_bak_bak b/resources/piece_ledger.json_bak_bak new file mode 100644 index 0000000..aa529be --- /dev/null +++ b/resources/piece_ledger.json_bak_bak @@ -0,0 +1,17 @@ +{ +ledger: +[ + 314491, + 314491, + 314491, + 314491, + 127947, + 389839, + 333441, + 175649, + 936089, + 936089, + 947477, + 947477 +] +} \ No newline at end of file diff --git a/resources/tmp/tmp_gui_state.json.json b/resources/tmp/tmp_gui_state.json.json new file mode 100644 index 0000000..b388a1d --- /dev/null +++ b/resources/tmp/tmp_gui_state.json.json @@ -0,0 +1,603 @@ +{ + "mus_seq": "[\n [\n [\n [ [ [ \"Rest\" ], [ \"Rest\" ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ] ], 0 ], \n [ [ [ \"Rest\" ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.75 ], \n [ [ [ 0, 0, 1, 0, 0, 0 ], [ \"Rest\" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.5 ], \n [ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.75 ], \n [ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.5 ], \n [ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.875 ], \n [ [ [ 0, 0, 1, 0, 0, 0 ], [ 0, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.625 ], \n [ [ [ 0, 0, 1, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0 ], \n [ [ [ 0, 0, 0, 0, 1, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.5 ]\n ],\n [\n [ [ [ 0, 0, 0, 0, 1, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 1, 0, -1, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.125 ], \n [ [ [ 0, 0, 0, 0, 1, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 1, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1 ], \n [ [ [ 0, 0, 0, 0, 1, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, -1, 0, 0, 1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ], \n [ [ [ 0, 0, 0, 0, 1, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.75 ], \n [ [ [ 0, 0, 0, 0, 1, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, -1, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.625 ], \n [ [ [ 0, 0, 0, 0, 1, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ -1, 0, 1, 0, 1, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.75 ], \n [ [ [ 0, 0, 0, 0, 1, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ -1, 0, 1, 0, 1, 0 ], [ \"Rest\" ] ], 0 ], \n [ [ [ \"Rest\" ], [ 1, 0, 0, -1, 0, 0 ], [ -1, 0, 1, 0, 1, 0 ], [ \"Rest\" ] ], 0 ], \n [ [ [ \"Rest\" ], [ \"Rest\" ], [ -1, 0, 1, 0, 1, 0 ], [ \"Rest\" ] ], 0 ], \n [ [ [ \"Rest\" ], [ \"Rest\" ], [ \"Rest\" ], [ \"Rest\" ] ], 1.375 ]\n ]\n ]\n]", + "motif_label": "motif", + "motif_panel": -1, + "seeds_label": "seeds", + "order": "[\n [ [ 3, 2 ], [ 0, 1, 1, 1, 1, 1, 0 ], [ ] ], \n [ [ 1, 0, 3 ], [ 2, 2, 2, 2, 2, 2 ], [ ] ]\n]", + "order_lock": 0, + "order_size_rslider": [ + 2, + 6 + ], + "order_size_input_max": 6, + "order_size_input_min": 2, + "order_size": -1, + "passages_size_rslider": [ + 0, + 10 + ], + "passages_size_input_max": 10, + "passages_size_input_min": 0, + "passages_size": -1, + "sus_weights": [ + null, + null, + null + ], + "range_matrix": [ + null, + null, + null, + null + ], + "instrumentation": -1, + "entrances_probs_sync": "entrances", + "entrances": -1, + "passages_probs_sync": "passages", + "passages": -1, + "exits_probs_sync": "exits", + "exits": -1, + "dur_panel": 0, + "durations": -1, + "passages_weights": [ + null, + null, + null, + null, + null + ], + "weights": -1, + "seeds_tab_panel": 1, + "order_seed_lock": 0, + "order_seed": 684642, + "dur_seed_lock": 0, + "dur_seed": 712392, + "weights_seed_lock": 0, + "weights_seed": 330807, + "seeds_panel": -1, + "root": -1, + "sus_weights/0_val_slider": 0.75, + "sus_weights/0_val_input": 0.75, + "sus_weights/0_val_label": 1, + "sus_weights/0_val": -1, + "sus_weights/1_val_slider": 0.69, + "sus_weights/1_val_input": 0.69, + "sus_weights/1_val_label": 2, + "sus_weights/1_val": -1, + "sus_weights/2_val_slider": 0.75, + "sus_weights/2_val_input": 0.75, + "sus_weights/2_val_label": 3, + "sus_weights/2_val": -1, + "passages_weights/0_val_slider": 0.75, + "passages_weights/0_val_input": 0.75, + "passages_weights/0_val_label": "step", + "passages_weights/0_val": -1, + "passages_weights/1_val_slider": 0.75, + "passages_weights/1_val_input": 0.75, + "passages_weights/1_val_label": "dc", + "passages_weights/1_val": -1, + "passages_weights/2_val_slider": 0.75, + "passages_weights/2_val_input": 0.75, + "passages_weights/2_val_label": "range", + "passages_weights/2_val": -1, + "passages_weights/3_val_slider": 0.75, + "passages_weights/3_val_input": 0.75, + "passages_weights/3_val_label": "registration", + "passages_weights/3_val": -1, + "passages_weights/4_val_slider": 0.75, + "passages_weights/4_val_input": 0.75, + "passages_weights/4_val_label": "hd", + "passages_weights/4_val": -1, + "range_matrix/0_val_input_min": -384, + "range_matrix/0_val_rslider": [ + -384, + 2400 + ], + "range_matrix/0_val_input_max": 2400, + "range_matrix/0_val": -1, + "range_matrix/1_val_input_min": -507, + "range_matrix/1_val_rslider": [ + -507, + 2400 + ], + "range_matrix/1_val_input_max": 2400, + "range_matrix/1_val": -1, + "range_matrix/2_val_input_min": -282, + "range_matrix/2_val_rslider": [ + -282, + 2237 + ], + "range_matrix/2_val_input_max": 2237, + "range_matrix/2_val": -1, + "range_matrix/3_val_input_min": -1200, + "range_matrix/3_val_rslider": [ + -1200, + 2053 + ], + "range_matrix/3_val_input_max": 2053, + "range_matrix/3_val": -1, + "entrances_probs_chord_val_slider": 0.75, + "entrances_probs_chord_val_input": 0.75, + "entrances_probs_chord_val_label": "chord prob", + "entrances_probs_chord_val": -1, + "entrances_probs_vals": [ + 0.75, + 0.5, + 2, + 0, + 0.5, + 0.26424870466321, + 0.75675675675676, + 0.5, + 0.5, + 0.58549222797927, + 0.72635135135135, + 1, + 0.5 + ], + "entrances_probs": -1, + "passages_probs_chord_val_slider": 0.75, + "passages_probs_chord_val_input": 0.75, + "passages_probs_chord_val_label": "chord prob", + "passages_probs_chord_val": -1, + "passages_probs_vals": [ + 0.75, + 0.5, + 2, + 0, + 0.5, + 0.20725388601036, + 0.68581081081081, + 0.24093264248705, + 0.34121621621622, + 0.5, + 0.5, + 0.67616580310881, + 0.81081081081081, + 1, + 0.5 + ], + "passages_probs": -1, + "exits_probs_chord_val_slider": 0.75, + "exits_probs_chord_val_input": 0.75, + "exits_probs_chord_val_label": "chord prob", + "exits_probs_chord_val": -1, + "exits_probs_vals": [ + 0.75, + 0.5, + 2, + 0, + 0.5, + 0.20725388601036, + 0.68581081081081, + 0.24093264248705, + 0.34121621621622, + 0.5, + 0.5, + 0.67616580310881, + 0.81081081081081, + 1, + 0.5 + ], + "exits_probs": -1, + "step_env_env_vals": [ + 0.5, + 2, + 0, + 0.5, + 0.5, + 0.5, + 1, + 0.5 + ], + "step_env_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.5, + 0.5 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "step_env_env_size": 3, + "step_env_env_flatten": 0, + "step_env_env_rslider": [ + 0.5, + 2 + ], + "step_env_env_input_max": 2, + "step_env_env_input_min": 0.5, + "step_env_env_mpos": "", + "step_env_env": -1, + "entrances_probs_dur_env_vals": [ + 0.5, + 2, + 0, + 0.5, + 0.26424870466321, + 0.75675675675676, + 0.5, + 0.5, + 0.58549222797927, + 0.72635135135135, + 1, + 0.5 + ], + "entrances_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.26424870466321, + 0.75675675675676 + ], + [ + 0.5, + 0.5 + ], + [ + 0.58549222797927, + 0.72635135135135 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "entrances_probs_dur_env_size": 5, + "entrances_probs_dur_env_flatten": 0, + "entrances_probs_dur_env_rslider": [ + 0.5, + 2 + ], + "entrances_probs_dur_env_input_max": 2, + "entrances_probs_dur_env_input_min": 0.5, + "entrances_probs_dur_env_mpos": "", + "entrances_probs_dur_env": -1, + "passages_probs_dur_env_vals": [ + 0.5, + 2, + 0, + 0.5, + 0.20725388601036, + 0.68581081081081, + 0.24093264248705, + 0.34121621621622, + 0.5, + 0.5, + 0.67616580310881, + 0.81081081081081, + 1, + 0.5 + ], + "passages_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.20725388601036, + 0.68581081081081 + ], + [ + 0.24093264248705, + 0.34121621621622 + ], + [ + 0.5, + 0.5 + ], + [ + 0.67616580310881, + 0.81081081081081 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "passages_probs_dur_env_size": 6, + "passages_probs_dur_env_flatten": 0, + "passages_probs_dur_env_rslider": [ + 0.5, + 2 + ], + "passages_probs_dur_env_input_max": 2, + "passages_probs_dur_env_input_min": 0.5, + "passages_probs_dur_env_mpos": "", + "passages_probs_dur_env": -1, + "exits_probs_dur_env_vals": [ + 0.5, + 2, + 0, + 0.5, + 0.20725388601036, + 0.68581081081081, + 0.24093264248705, + 0.34121621621622, + 0.5, + 0.5, + 0.67616580310881, + 0.81081081081081, + 1, + 0.5 + ], + "exits_probs_dur_env_canvas": [ + [ + 0, + 0.5 + ], + [ + 0.20725388601036, + 0.68581081081081 + ], + [ + 0.24093264248705, + 0.34121621621622 + ], + [ + 0.5, + 0.5 + ], + [ + 0.67616580310881, + 0.81081081081081 + ], + [ + 1, + 0.5 + ], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "exits_probs_dur_env_size": 6, + "exits_probs_dur_env_flatten": 0, + "exits_probs_dur_env_rslider": [ + 0.5, + 2 + ], + "exits_probs_dur_env_input_max": 2, + "exits_probs_dur_env_input_min": 0.5, + "exits_probs_dur_env_mpos": "", + "exits_probs_dur_env": -1 +} \ No newline at end of file diff --git a/resources/tmp/tmp_mus_model.json b/resources/tmp/tmp_mus_model.json new file mode 100644 index 0000000..13de2c1 --- /dev/null +++ b/resources/tmp/tmp_mus_model.json @@ -0,0 +1,113 @@ +{ +"music_data": +[ + [ + [ + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 1.75 ], + [ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 4.625 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.875 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 4.5 ] + ], + [ + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.375 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ] ], 1.25 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ -1, 0, 0, 0, 0, 1 ] ], 1.875 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, -1, -1, 0, 0 ] ], 1.875 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 1.625 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, -1, 0, 1, 0 ] ], 0.5 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ] ], 1.875 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ] ], 0.75 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 1, -1, 0, 0, 0 ] ], 1.875 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ] ], 0.875 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 4.375 ] + ], + [ + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, -1, 0, 1, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 1 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ 1, -1, -1, 0, 1, 0 ], [ 0, 0, -1, 0, 1, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 1.5 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ], [ 0, 0, -1, 0, 1, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 0.625 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ], [ 0, 1, -1, 0, 0, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 1 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ], [ 1, 0, -1, 0, -1, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 1.75 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 1.25 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ], [ 2, -1, -1, 0, 0, -1 ], [ 1, -1, -1, 0, 0, 0 ] ], 0.75 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ], [ 1, -1, -1, 0, 1, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 1.625 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ], [ 1, 0, -2, 0, 0, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 3.375 ] + ], + [ + [ [ [ "Rest" ], [ 1, 0, -1, 0, 0, 0 ], [ 1, 0, -2, 0, 0, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 1.125 ], + [ [ [ "Rest" ], [ 1, 0, -1, 0, 0, 0 ], [ 0, 0, -1, 1, 0, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 0.75 ], + [ [ [ "Rest" ], [ 1, 0, -1, 0, 0, 0 ], [ 0, 1, -1, 0, 0, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 0.875 ], + [ [ [ "Rest" ], [ 1, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 0.625 ], + [ [ [ "Rest" ], [ 1, 0, -1, 0, 0, 0 ], [ 1, 0, -1, 0, -1, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 3.625 ] + ], + [ + [ [ [ "Rest" ], [ 1, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 1, -1, -1, 0, 0, 0 ] ], 2 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 1, -1, -1, 0, 0, 0 ] ], 0 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ 2, -1, -2, 0, 0, 0 ], [ "Rest" ], [ 1, -1, -1, 0, 0, 0 ] ], 5 ] + ], + [ + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 1, -1, -1, 0, 0, 0 ] ], 1.125 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 1, 0, -1, 0, -1, 0 ], [ 1, -1, -1, 0, 0, 0 ] ], 1 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 1, 0, -1, 0, -1, 0 ], [ 0, 0, -1, 0, 1, 0 ] ], 1.875 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 1, 0, -1, 0, -1, 0 ], [ 0, 1, -1, 0, 0, 0 ] ], 1.125 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 1, 0, -1, 0, -1, 0 ], [ 1, 0, -2, 0, 0, 0 ] ], 1.875 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 1, 0, -1, 0, -1, 0 ], [ 0, 0, -1, 0, 0, 1 ] ], 0.625 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 1, 0, -1, 0, -1, 0 ], [ 0, 0, -1, 1, 0, 0 ] ], 4.25 ] + ], + [ + [ [ [ 0, 0, -1, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 0, 0, -1, 1, 0, 0 ] ], 1.25 ], + [ [ [ 0, 0, -1, 0, 0, 0 ], [ 2, -1, -2, 0, 0, 0 ], [ "Rest" ], [ 0, 0, -1, 1, 0, 0 ] ], 1 ], + [ [ [ 1, -1, -2, 0, 0, 0 ], [ 2, -1, -2, 0, 0, 0 ], [ "Rest" ], [ 0, 0, -1, 1, 0, 0 ] ], 1.875 ], + [ [ [ 0, -1, -2, 1, 0, 0 ], [ 2, -1, -2, 0, 0, 0 ], [ "Rest" ], [ 0, 0, -1, 1, 0, 0 ] ], 3.125 ] + ], + [ + [ [ [ 0, -1, -2, 1, 0, 0 ], [ 2, -1, -2, 0, 0, 0 ], [ 1, 0, -1, 0, -1, 0 ], [ 0, 0, -1, 1, 0, 0 ] ], 3.75 ], + [ [ [ 0, -1, -2, 1, 0, 0 ], [ 1, 0, -1, 0, -1, 1 ], [ 1, 0, -1, 0, -1, 0 ], [ 0, 0, -1, 1, 0, 0 ] ], 1.375 ], + [ [ [ 0, -1, -2, 1, 0, 0 ], [ 1, 0, -1, 0, -1, 1 ], [ 1, 0, -1, 0, -1, 0 ], [ 1, 0, 0, 0, -1, 0 ] ], 0.75 ], + [ [ [ 0, -1, -2, 1, 0, 0 ], [ 1, 0, -1, 0, -1, 1 ], [ 1, 0, -1, 0, -1, 0 ], [ 1, -1, -2, 1, 0, 0 ] ], 1.5 ], + [ [ [ 0, -1, -2, 1, 0, 0 ], [ 1, 0, -1, 0, -1, 1 ], [ 1, 0, -1, 0, -1, 0 ], [ 2, 0, -1, 0, -2, 0 ] ], 1 ], + [ [ [ 0, -1, -2, 1, 0, 0 ], [ 1, 0, -1, 0, -1, 1 ], [ 1, 0, -1, 0, -1, 0 ], [ 2, -1, -2, 0, 0, 0 ] ], 1.125 ], + [ [ [ 0, -1, -2, 1, 0, 0 ], [ 1, 0, -1, 0, -1, 1 ], [ 1, 0, -1, 0, -1, 0 ], [ 2, -1, -1, 0, -1, 0 ] ], 1.125 ], + [ [ [ 0, -1, -2, 1, 0, 0 ], [ 1, 0, -1, 0, -1, 1 ], [ 1, 0, -1, 0, -1, 0 ], [ 2, 0, -1, 0, -1, -1 ] ], 5.25 ], + [ [ [ 0, -1, -2, 1, 0, 0 ], [ 1, 0, -1, 0, -1, 1 ], [ "Rest" ], [ 2, 0, -1, 0, -1, -1 ] ], 0 ], + [ [ [ 0, -1, -2, 1, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 2, 0, -1, 0, -1, -1 ] ], 1.5 ], + [ [ [ 0, -1, -2, 1, 0, 0 ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 1.75 ], + [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 4.625 ] + ] + ] +], +"last_changes": +[ + [ [ 0, -1, -2, 1, 0, 0 ], [ 1, 0, -1, 0, -1, 1 ], [ 1, 0, -1, 0, -1, 0 ], [ 1, -1, -2, 1, 0, 0 ] ], + [ [ 0, -1, -2, 1, 0, 0 ], [ 1, 0, -1, 0, -1, 1 ], [ 1, 0, -1, 0, -1, 0 ], [ 2, 0, -1, 0, -2, 0 ] ], + [ [ 0, -1, -2, 1, 0, 0 ], [ 1, 0, -1, 0, -1, 1 ], [ 1, 0, -1, 0, -1, 0 ], [ 2, -1, -2, 0, 0, 0 ] ], + [ [ 0, -1, -2, 1, 0, 0 ], [ 1, 0, -1, 0, -1, 1 ], [ 1, 0, -1, 0, -1, 0 ], [ 2, -1, -1, 0, -1, 0 ] ], + [ [ 0, -1, -2, 1, 0, 0 ], [ 1, 0, -1, 0, -1, 1 ], [ 1, 0, -1, 0, -1, 0 ], [ 2, 0, -1, 0, -1, -1 ] ] +], +"cur_uid": "tmp", +"ref_uid": "nil", +"order_seed": 739163, +"dur_seed": 513075, +"motifs_seed": 310413, +"entrances_probs_vals": [ 0.33687943262411, 1.91, 4.44, 0.5, 2, 0, 0.5, 0.24509803921569, 0.89189189189189, 0.5, 1, 0.5, 0.5, 0.8562091503268, 0.69932432432432, 1, 0.5 ], +"passages_probs_vals": [ 0.33687943262411, 1.91, 4.44, 0.5, 2, 0, 0.5, 0.24509803921569, 0.89189189189189, 0.5, 1, 0.5, 0.5, 0.8562091503268, 0.69932432432432, 1, 0.5 ], +"exits_probs_vals": [ 0.33687943262411, 1.91, 4.44, 0.5, 2, 0, 0.5, 0.24509803921569, 0.89189189189189, 0.5, 1, 0.5, 0.5, 0.8562091503268, 0.69932432432432, 1, 0.5 ], +"ranges": [ [ -1200, 2400 ], [ -1200, 2400 ], [ -1200, 2400 ], [ -1200, 2400 ] ], +"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ], +"order": +[ + [ [ 3, 2 ], [ 0, 1, 1 ], [ ] ], + [ [ 2, 0 ], [ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ], [ 1 ] ], + [ [ 3, 0 ], [ 2, 1, 1, 2, 2, 2, 2, 2, 2 ], [ ] ], + [ [ 3, 1 ], [ 2, 2, 2, 2 ], [ 0 ] ], + [ [ 0, 3 ], [ 1 ], [ 2 ] ], + [ [ 2, 0 ], [ 3, 3, 3, 3, 3 ], [ 1 ] ], + [ [ 1, 3 ], [ 0, 0 ], [ 2 ] ], + [ [ 0, 2 ], [ 1, 3, 3, 3, 3, 3, 3 ], [ ] ] +], +"sus_weights": [ 0, 0.82, 0 ], +"order_size": [ 1, 10 ], +"passages_size": [ 0, 10 ], +"motif_edited": "false", +"order_edited": "false" +} \ No newline at end of file diff --git a/supercollider/seeds_and_ledgers_main.scd b/supercollider/seeds_and_ledgers_main.scd new file mode 100644 index 0000000..caa982a --- /dev/null +++ b/supercollider/seeds_and_ledgers_main.scd @@ -0,0 +1,757 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck, +msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON; + +// model vars +//(model and global vars mostly set by OSC funcs +var seq, lastXChanges, +curUID, refUID, orderSeed, durSeed, motifSeed, +entrancesProbVals, passagesProbVals, exitsProbVals, +ranges, passagesWeights, orders, susWeights, orderSize, passagesSize, +motifEdited, orderEdited; + +// model aux vars +var entrancesDurFunc, passagesDurFunc, exitsDurFunc; + +// other global vars +var popSize, exPath, dir, primes, dims, tuples, +group, player, ledgerPath, ledger, currentlyPlayingUID; + + +// install JSON quark +if(Quarks.isInstalled("JSONlib").not, { + Quarks.install("https://github.com/musikinformatik/JSONlib.git"); + thisProcess.recompile; + //HelpBrowser.openHelpFor("Classes/JSONlib"); +}); + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genDurFunc = {arg chordProb, minPad, maxPad, minDur, maxDur, envData, seed; + var env, pTable, durFunc; + env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + [chordProb, minPad, maxPad, minDur, maxDur, envData].postln; + durFunc = {arg allowChord, pad = false; + var res; + res = if(allowChord.not, { + pTable.tableRand * (maxDur - minDur) + minDur + }, { + if(1.0.rand < chordProb, {0}, {pTable.tableRand * (maxDur - minDur) + minDur}); + }).round(0.125); + if(pad, {res = res + rrand(minPad.asFloat, maxPad.asFloat).round(0.125)}); + if(res.asInteger == res, {res = res.asInteger}); + res + }; + seedFunc.value(durFunc, seed); +}; + +genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5; + ((maxMotifLength - minMotifLength).rand + minMotifLength).collect({ + var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order; + noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum); + noProgIns = (popSize - noSusIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] + }); +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = passagesWeights; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, flatOrder, res, isInChord, allowChord, pad, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + flatOrder = silent ++ sus ++ prog; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + isInChord = popSize.collect({false}); + allowChord = false; + pad = false; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + flatOrder.do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + + if((sus ++ silent).includes(ins), { + allowChord = (ins != sus.last); + pad = (ins == sus.last); + }, { + if(i < (flatOrder.size - 1), { + allowChord = (isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not; + pad = false; + }, { + allowChord = false; + pad = true + }); + }); + if((orderIndex == 0) && sus.includes(ins), { + dur = entrancesDurFunc.value(allowChord, pad); + }, { + dur = passagesDurFunc.value(allowChord, pad); + }); + if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})}); + + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + + // pad ending + if(orderIndex == (orders.size - 1), { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + allowChord = (voices != popSize.collect({["Rest"]})); + pad = allowChord.not; + dur = exitsDurFunc.value(allowChord, pad); + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = { + var repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + + orders.do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +/* +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~addr.sendMsg(~indexPath, ~indexMsg); + ~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3)); + //~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln); + }; +}); +*/ + +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~msg.postln; + ~addr.sendMsg(~path, *~msg); + }; +}); + +genPatterns = {arg inSeq, addr; + var voices, durs, patterns, res, indices, sectionDurs, msg, ids, seq; + seq = inSeq.collect({arg mSeq; mSeq[0]}); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + msg = inSeq.collect({arg mSeq, m; mSeq[1..]}); + //ids = inSeq.collect({arg mSeq, m; mSeq[2]}); + sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum}); + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ) + }) ++ + [ + Pbind( + \type, \osc, + \addr, addr, + //\indexPath, "/cur_play_index", + //\indexMsg, Pseq(indices, 1), + //\seqPath, "/mus_seq", + //\seqMsg, Pseq(seq, 1), + \path, "/playing", + \msg, Pseq(msg, 1), + \dur, Pseq(sectionDurs, 1) + ); + ] + ); + res +}; + +/* +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; +*/ + + +//------resource management funcs + +genUID = {Date.seed.asHexString.toLower}; + +seedFunc = {arg func, seed; + var funcArgs, next; + next = Routine({loop{func.valueArray(funcArgs).yield }}); + next.randSeed_(seed); + {arg ...args; funcArgs = args; next.value} +}; + +stringifyToDepth = {arg data, maxDepth = 1; + var prettyString = "", rCount = 0, writeArray, indent; + + if(maxDepth == 0, { + data.asCompileString + }, { + indent = {arg size; size.collect({" "}).join("")}; + writeArray = {arg array; + prettyString = prettyString ++ indent.value(rCount) ++ "[\n"; + rCount = rCount + 1; + if(rCount < maxDepth, { + array.do({arg subArray; writeArray.value(subArray)}); + }, { + prettyString = prettyString ++ array.collect({arg subArray; + indent.value(rCount + 1) ++ subArray.asCompileString + }).join(",\n"); + }); + rCount = rCount - 1; + prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n"; + }; + + writeArray.value(data); + prettyString.replace(",\n\n", "\n").drop(-2); + }) +}; + +sanityCheck = {arg motif, index; + //print functions = very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true; + var res; + + res = in; + if(res.isNil.not, { + if((res.isArray && res.isString.not), { + res = res.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + if(escapeSingleQuotes, {res = res.replace("\'", "")}); + if(escapeDoubleQuotes, {res = res.replace("\"", "")}); + res = res.replace("Rest", "\"Rest\""); + res = res.interpret; + }, { + //res.postln; + if(res.every({arg char; char.isDecDigit}), {res = res.asInteger}); + }); + }); + res +}; + +writeResources = {arg path; + var file, nameSpaces, modelItems, resString; + file = File(path,"w"); + + nameSpaces = [ + "music_data", "last_changes", + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size", + "motif_edited", "order_edited" + ]; + + modelItems = [ + seq, lastXChanges, + curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize, + motifEdited, orderEdited + ]; + + resString = [nameSpaces, modelItems].flop.collect({arg item; + var nameSpace, modelItem, depth = 0, insert = " "; + # nameSpace, modelItem = item; + if(nameSpace == "music_data", {depth = 3; insert = "\n"}); + if(nameSpace == "last_changes", {depth = 1; insert = "\n"}); + if(nameSpace == "order", {depth = 1; insert = "\n"}); + if((nameSpace == "ref_uid") && (modelItem == nil), {modelItem = "nil"}); + "\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem, depth) + }).join(",\n"); + + resString = "{\n" ++ resString ++ "\n}"; + + file.write(resString); + file.close; + resString +}; + +loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)}; + +loadModelJSON = {arg jsonObject; + var nameSpaces, data; + + //model = File(path, "r").readAllString.parseJSON; + + nameSpaces = [ + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size", + "motif_edited", "order_edited" + ]; + + data = nameSpaces.collect({arg nS; msgInterpret.value(jsonObject[nS])}); + + //data.postln; + + # curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize, + motifEdited, orderEdited = data; + + popSize = ranges.size; +}; + +loadLedgerFile = {arg path; + ledgerPath = path; + loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON) +}; + +loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]}; + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +//popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +//refUID = nil; +group = Group.new; +loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json"); +//passagesWeights = [1, 1, 1, 1, 1]; +//susWeights = [1, 1, 1]; + + +//------OSC funcs + +OSCdef(\load_ledger, {arg msg, time, addr, port; + loadLedgerFile.value(msg[1].asString); +}, \load_ledger); + +OSCdef(\load_model, {arg msg, time, addr, port; + loadModelFile.value(msg[1].asString); +}, \load_model); + + +OSCdef(\generate, {arg msg, time, addr, port; + var path, durSeeds, musPath, modelString; + msg.postln; + + path = msg[1].asString; + + loadModelFile.value(path); + + //refUID.postln; + + loadLedgerFile.value(ledgerPath); + if(ledger == nil, {ledger = ["tmp"]}); + if(ledger.last != "tmp", {ledger = ledger.add("tmp")}); + + lastXChanges = if(refUID == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln; + entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..4] ++ [entrancesProbVals[5..]] ++ [durSeeds[0]]); + passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..4] ++ [passagesProbVals[5..]] ++ [durSeeds[1]]); + exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..4] ++ [exitsProbVals[5..]] ++ [durSeeds[2]]); + + if(orders == nil, { + orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize); + //addr.sendMsg("/order", stringifyToDepth.value(orders, 1)); + }); + seq = seedFunc.value(genMotif, motifSeed).value; + + modelString = writeResources.value(path); + + //addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3)); + addr.sendMsg("/generated", path, modelString); +}, \generate); + + +OSCdef(\commit, {arg msg, time, addr, port; + var newLedger, modelPath, musString, musFile, test1, test2; + msg.postln; + + /* + test1 = msg[1].asString.parseJSON; + test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile; + msgInterpret.value(test1["music"])[0][0][0][1].class.postln; + msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln; + (test1["music"] == test2["music_data"]).postln; + */ + + curUID = genUID.value; + File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath); + File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath); + + modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; + writeResources.value(modelPath); + + File.delete(ledgerPath ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath, "w"); + ledger = ledger.drop(-1).add(curUID); + newLedger.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}"); + newLedger.close; + + addr.sendMsg("/committed", curUID, ledgerPath); + //refUID = curUID; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + // the cued sequence can now be read from file, so this can be cleaned up + var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; + pSeq = []; + cuedSeek = (seq != nil); + indexStart = msg[2].asInteger; + indexEnd = ledger.size - if(cuedSeek, {2}, {1}); + //ledger.postln; + if(((indexStart == (ledger.size - 1)) && cuedSeek).not, { + ledger[indexStart..indexEnd].do({arg uid, index; + var path, file; + path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath; + file = File(path, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, indexStart + index, uid]); + file.close; + }); + }); + if(cuedSeek, { + var path, file; + path = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath; + file = File(path, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]); + file.close; + }); + patterns = genPatterns.value(pSeq, addr); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); + //Out.ar([0, 1], sig1 * EnvGen.kr(Env.asr(dur, 0.3, 1), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; + +1223423434123.asHexString.toLower + +Date.getDate.rawSeconds +Date.seed.asHexString.toLower + +n = NetAddr("localhost", 8080); +n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals"); \ No newline at end of file diff --git a/supercollider/seeds_and_ledgers_main_dict.scd b/supercollider/seeds_and_ledgers_main_dict.scd new file mode 100644 index 0000000..5b87524 --- /dev/null +++ b/supercollider/seeds_and_ledgers_main_dict.scd @@ -0,0 +1,727 @@ +( +// helper funcs +var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq; + +// score funcs +var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore; + +// subroutines +var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc; + +// primary routines +var genMotif, genSecondarySeq; + +// audition funcs +var genPatterns, genMidiPatterns; + +// resource management funcs +var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck, +msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON; + +// model vars +//(model and global vars mostly set by OSC funcs +var curUID, refUID, orderSeed, durSeed, motifSeed, +entrancesProbVals, passagesProbVals, exitsProbVals, +ranges, orders, susWeights, passagesWeights, passagesSize, orderSize, +model; + +// model aux vars +var entrancesDurFunc, passagesDurFunc, exitsDurFunc; + +// other global vars +var lastXChanges, popSize, exPath, dir, primes, dims, tuples, +seq, group, player, ledgerPath, ledger, currentlyPlayingUID; + + +// install JSON quark +if(Quarks.isInstalled("JSONlib").not, { + Quarks.install("https://github.com/musikinformatik/JSONlib.git"); + thisProcess.recompile; + //HelpBrowser.openHelpFor("Classes/JSONlib"); +}); + + +//------helper funcs + +hsArrayToCents = { + arg hsArray; + hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum +}; + +pDist = { + arg array1, array2, signed = false; + var pDistance; + pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2); + if(signed, {pDistance}, {abs(pDistance)}) +}; + +hdSum = { + arg hsArrays; + var size, distances, mean; + size = hsArrays.size; + distances = (size - 1).collect({arg i; + ((i + 1)..(size - 1)).collect({arg j; + abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsChordalDistance = { + arg hsArrays1, hsArrays2; + var size, distances, mean; + size = hsArrays1.size; + distances = hsArrays1.size.collect({arg i; + hsArrays2.size.collect({arg j; + abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum + }); + }).flat; + mean = distances.sum / distances.size; + distances.sum + //mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean) +}; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +//------score funcs + +/* +isInRange = { + arg hsArray, min, max; + var cents; + cents = hsArrayToCents.value(hsArray); + (cents >= min) && (cents <= max) +}; +*/ + +spacingScore = { + arg hsArrays, min; + var centsArray; + centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b}); + centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum; +}; + +rangeScore = { + arg hsArray1, hsArray2, min, max, low, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + if((pDistance >= min) && (pDistance <= max), {1}, {low}); +}; + +intervalScore = { + arg hsArray1, hsArray2, mean, sd, signed = false; + var pDistance; + pDistance = pDist.value(hsArray1, hsArray2, signed); + pDistance.gaussCurve(1, mean, sd) +}; + +inclusionScore = { + arg array, test, min = 0.01; + if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1}); +}; + + +//------subroutines + +genTuples = { + var tuples; + tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)}); + tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten; +}; + +initVoices = { + var init, voicesInit; + voicesInit = popSize.collect({dims.collect({0})}); + /* + voicesInit = [dims.collect({0})]; + (popSize - 1).do({ + arg rep, new; + rep = dims.rand; + new = voicesInit.last.deepCopy; + new[rep] = new[rep] + [-1, 1].choose(); + voicesInit = voicesInit.add(new); + }); + */ + voicesInit.deepCopy; +}; + +genDurFunc = {arg chordProb, min, max, envData, seed; + var env, pTable, durFunc; + env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray; + pTable = env.asRandomTable; + durFunc = {arg allowChord; + var res; + res = if(allowChord.not, { + pTable.tableRand * (max - min) + min + }, { + if(1.0.rand < chordProb, {0}, {pTable.tableRand * (max - min) + min}); + }).round(0.125); + if(res.asInteger == res, {res = res.asInteger}); + res + }; + seedFunc.value(durFunc, model["dur_seed"]); +}; + +genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5; + ((maxMotifLength - minMotifLength).rand + minMotifLength).collect({ + var noProgIns, noSusIns, noSilentIns, prog, sus, silent; + noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum); + noProgIns = (popSize - noSusIns).rand + 1; + noSilentIns = popSize - noSusIns - noProgIns; + + # prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]); + + prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble); + if(silent == nil, {silent = []}); + [sus.scramble, prog, silent.scramble] + }); +}; + +updateVoices = {arg ins, sus; + var voices, candidates, nWeights, nProbs, sel; + + voices = lastXChanges.deepCopy.last; + + candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten; + candidates = difference(candidates.asSet, voices.asSet).asList; + nProbs = candidates.collect({arg candidate; + var ranges, stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore; + + ranges = model["ranges"]; + //stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1); + stepScore = intervalScore.value(voices[ins], candidate, 100, 100); + recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0); + isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true); + regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300); + hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2); + //maybe what you want here is a vector to another root and then favoring movement towards it. + //distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2); + + [stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore] + }); + + nWeights = model["passages_weights"]; + + //this handles nWeights of 0; mainly for testing + nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop; + nWeights = nWeights.select({arg weight; weight != 0}); + nProbs = nProbs.flop.collect({arg scores, s; + if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]}) + }); + nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum; + + sel = candidates.wchoose(nProbs); + + voices[ins] = sel; + lastXChanges = lastXChanges.add(voices).keep(-5); +}; + +genSubMotif = {arg order, lastState, repeatLast = false, startFromLast = false, isLastOrder = false; + var sus, prog, silent, flatOrder, res, isInChord, allowChord, lastXChangesHold, voices, adder; + # sus, prog, silent = order; + flatOrder = silent ++ sus ++ prog; + lastXChangesHold = lastXChanges.deepCopy; + voices = lastState.deepCopy; + isInChord = popSize.collect({false}); + allowChord = false; + res = []; + "------generating motif".postln; + //need to figure out here if voices move between motifs + flatOrder.do({arg ins, i; + + if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)}); + adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]}); + + if(voices[ins] != adder, { + var dur; + allowChord = if((sus ++ silent).includes(ins), { + (sus ++ silent).includes(ins) && (ins != sus.last); + }, { + if(i < (flatOrder.size - 1), {(isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not}, {false}); + }); + dur = passagesDurFunc.value(allowChord); + if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})}); + + voices[ins] = adder; + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + + // pad ending + if(isLastOrder, { + (0..(popSize-1)).scramble.do({arg ins; + if(res.last.first[ins] != ["Rest"], { + var dur; + voices[ins] = ["Rest"]; + allowChord = (voices != popSize.collect({["Rest"]})); + dur = passagesDurFunc.value(allowChord); + res = res.add([voices.deepCopy.postln, dur]); + }); + }); + }); + + //format and return + if(startFromLast, {lastXChanges = lastXChangesHold}); + res; +}; + + +//------primary routines + +genMotif = { + var repeats, fSeq; + + repeats = 1; + fSeq = []; + + repeats.do({arg index; + var motif; + + motif = []; + + model["orders"].do({arg order, o; + var lastState, subMotif; + lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first}); + subMotif = genSubMotif.value(order, lastState, isLastOrder: o == (orders.size - 1)); + motif = motif.add(subMotif); + + }); + + sanityCheck.value(motif, index); + + fSeq = fSeq.add(motif); + }); + fSeq +}; + +genSecondarySeq = {arg seq; + var curdles, fSeq; + curdles = []; + while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]}); + + fSeq = seq.clumps(curdles).collect({arg clump, m; + var repeats, paddedSeq; + + //add rest + paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]); + + //implement repeats + repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum); + repeats.collect({paddedSeq}); + }); + fSeq +}; + + +//------audition funcs + +Event.addEventType(\osc, { + if (~addr.postln.notNil) { + ~addr.sendMsg(~indexPath, ~indexMsg); + ~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3)); + //~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln); + }; +}); + +genPatterns = {arg inSeq, addr; + var voices, durs, patterns, res, indices, sectionDurs, ids, seq; + seq = inSeq.collect({arg mSeq; mSeq[0]}); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + indices = inSeq.collect({arg mSeq, m; mSeq[1]}); + ids = inSeq.collect({arg mSeq, m; mSeq[2]}); + sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum}); + res = Ppar( + voices.flop.collect({arg voice; + var clumps, hdScores, freqs, fDurs; + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \instrument, \test, + \group, group, + \freq, Pseq(freqs, 1), + \dur, Pseq(fDurs, 1), + \sustain, Pseq(fDurs, 1) + ) + }) ++ + [ + Pbind( + \type, \osc, + \addr, addr, + \indexPath, "/cur_play_index", + \indexMsg, Pseq(indices.postln, 1), + \seqPath, "/mus_seq", + \seqMsg, Pseq(seq, 1), + \dur, Pseq(sectionDurs, 1) + ); + ] + ); + res +}; + +/* +genMidiPatterns = {arg seq; + var voices, durs, patterns, res, mOut, pbRange; + pbRange = 1; //semitones - change this as needed for your situation + mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency); + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + res = Ppar( + voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs; + + mOut.program(v, 70); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + + Pbind( + \type, \midi, + \chan, v, + \noteval, Pseq(freqs.cpsmidi - 24, 1), + \note, Pfunc({ | event | event[\noteval].floor }), + \dur, Pseq(fDurs, 1), + \midiout, mOut, + \amp, 1, + \bend, Pfunc({ + | event | + if (event[\note].isRest.not) { + var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger; + m.bend(v, pitchbendvalue); + }; + 0; // return something other than nil to avoid stopping the pattern + }), + ); + }); + ); + res +}; +*/ + + +//------resource management funcs + +genUID = {Date.seed.asHexString.toLower}; + +seedFunc = {arg func, seed; + var funcArgs, next; + next = Routine({loop{func.valueArray(funcArgs).yield }}); + next.randSeed_(seed); + {arg ...args; funcArgs = args; next.value} +}; + +stringifyToDepth = {arg data, maxDepth = 1; + var prettyString = "", rCount = 0, writeArray, indent; + + if(maxDepth == 0, { + data.asCompileString + }, { + indent = {arg size; size.collect({" "}).join("")}; + writeArray = {arg array; + prettyString = prettyString ++ indent.value(rCount) ++ "[\n"; + rCount = rCount + 1; + if(rCount < maxDepth, { + array.do({arg subArray; writeArray.value(subArray)}); + }, { + prettyString = prettyString ++ array.collect({arg subArray; + indent.value(rCount + 1) ++ subArray.asCompileString + }).join(",\n"); + }); + rCount = rCount - 1; + prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n"; + }; + + writeArray.value(data); + prettyString.replace(",\n\n", "\n").drop(-2); + }) +}; + +sanityCheck = {arg motif, index; + //print functions = very helpful + ("----------" + index + "------------").postln; + + motif.flatten.do({arg val, v; + if(v > 0, { + if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln}); + if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln}); + }); + val.postln + }); + "***********".postln; +}; + +msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true; + var res; + + res = in; + if(res.isNil.not, { + if((res.isArray && res.isString.not), { + res = res.asCompileString; + res = res.replace(" ", "").replace("\n", "").replace("\t", ""); + if(escapeSingleQuotes, {res = res.replace("\'", "")}); + if(escapeDoubleQuotes, {res = res.replace("\"", "")}); + res = res.replace("Rest", "\"Rest\""); + res = res.interpret; + }, { + //res.postln; + if(res.every({arg char; char.isDecDigit}), {res = res.asInteger}); + }); + }); + res +}; + +writeResources = {arg path; + var file, nameSpaces, modelItems, resString; + file = File(path,"w"); + + nameSpaces = [ + "music_data", "last_changes", + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + modelItems = [ + seq, lastXChanges, + curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize + ]; + + resString = [nameSpaces, modelItems].flop.collect({arg item; + var nameSpace, modelItem, depth = 0, insert = " "; + # nameSpace, modelItem = item; + if(nameSpace == "music_data", {depth = 3; insert = "\n"}); + if(nameSpace == "last_changes", {depth = 1; insert = "\n"}); + if(nameSpace == "order", {depth = 1; insert = "\n"}); + "\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem.postln, depth).postln + }).join(",\n"); + + resString = "{\n" ++ resString ++ "\n}"; + + file.write(resString); + file.close; + resString +}; + +loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)}; + +loadModelJSON = {arg jsonObject; + var nameSpaces, data; + + //model = File(path, "r").readAllString.parseJSON; + + nameSpaces = [ + "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed", + "entrances_probs_vals","passages_probs_vals", "exits_probs_vals", + "ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size" + ]; + + //data = nameSpaces.collect({arg nS; msgInterpret.value(jsonObject[nS]).postln}); + model = Dictionary.with(*nameSpaces.collect({arg nS; nS -> msgInterpret.value(jsonObject[nS]).postln})); + + data.postln; + + # curUID, refUID, orderSeed, durSeed, motifSeed, + entrancesProbVals, passagesProbVals, exitsProbVals, + ranges, passagesWeights, orders, susWeights, orderSize, passagesSize = data; + + popSize = ranges.size; +}; + +loadLedgerFile = {arg path; + ledgerPath = path; + loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON) +}; + +loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]}; + +//------global vars + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; +//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]]; +exPath = thisProcess.nowExecutingPath; +dir = exPath.dirname; +//popSize = 4; +dims = primes.size; +tuples = genTuples.value(); +//refUID = nil; +group = Group.new; +loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json"); +//passagesWeights = [1, 1, 1, 1, 1]; +//susWeights = [1, 1, 1]; + + +//------OSC funcs + +OSCdef(\load_ledger, {arg msg, time, addr, port; + loadLedgerFile.value(msg[1].asString); +}, \load_ledger); + +OSCdef(\load_model, {arg msg, time, addr, port; + loadModelFile.value(msg[1].asString); +}, \load_model); + + +OSCdef(\generate, {arg msg, time, addr, port; + var path, refUID, musPath, modelString; + msg.postln; + + path = msg[1].asString; + + loadModelFile.value(path); + + //refUID.postln; + refUID = model["ref_uid"]; + + loadLedgerFile.value(ledgerPath); + if(ledger == nil, {ledger = ["tmp"]}); + if(ledger.last != "tmp", {ledger = ledger.add("tmp")}); + + lastXChanges = if(refUID == nil, { + [initVoices.value().deepCopy]; + }, { + var file; + file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r"); + msgInterpret.value(file.readAllString.parseJSON["last_changes"]); + }); + + # entrancesDurFunc, passagesDurFunc, exitsDurFunc = ["entrances", "passages", "exits"].collect({arg nsPre; + var probsVals = model[nsPre + "_probs_vals"]; + genDurFunc.valueArray(probsVals[..2] ++ [probsVals[3..]]); + }); + + /* + entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..2] ++ [entrancesProbVals[3..]]); + passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..2] ++ [passagesProbVals[3..]]); + exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..2] ++ [exitsProbVals[3..]]); + */ + + if(orders == nil, { + orders = seedFunc.value(genOrders, model["order_seed"]).valueArray(orderSize ++ passagesSize); + //addr.sendMsg("/order", stringifyToDepth.value(orders, 1)); + }); + seq = seedFunc.value(genMotif, model["motif_seed"]).value; + + modelString = writeResources.value(path); + + //addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3)); + addr.sendMsg("/generated", path, modelString); +}, \generate); + + +OSCdef(\commit, {arg msg, time, addr, port; + var newLedger, modelPath, musString, musFile, test1, test2; + msg.postln; + + /* + test1 = msg[1].asString.parseJSON; + test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile; + msgInterpret.value(test1["music"])[0][0][0][1].class.postln; + msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln; + (test1["music"] == test2["music_data"]).postln; + */ + + curUID = genUID.value; + model["cur_uid"] = curUID; + File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath); + File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath); + + modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; + writeResources.value(modelPath); + + File.delete(ledgerPath.postln ++ "_bak"); + File.copy(ledgerPath, ledgerPath ++ "_bak"); + File.delete(ledgerPath); + newLedger = File(ledgerPath.postln, "w"); + ledger = ledger.postln.drop(-1).add(curUID); + newLedger.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}"); + newLedger.close; + + addr.sendMsg("/committed", curUID, ledgerPath); + //refUID = curUID; +}, \commit); + +OSCdef(\transport, {arg msg, time, addr, port; + msg.postln; + if(msg[1] == 0, { + player.stop; + group.set(\gate, 0); + }, { + // the cued sequence can now be read from file, so this can be cleaned up + var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; + pSeq = []; + cuedSeek = (seq != nil); + indexStart = msg[2].asInteger; + indexEnd = ledger.size - if(cuedSeek, {2}, {1}); + ledger.postln; + if(((indexStart == (ledger.size - 1)) && cuedSeek).not, { + ledger[indexStart..indexEnd].do({arg uid, index; + var file; + (indexStart + index).postln; + file = File((dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath, "r"); + pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), indexStart + index, uid]); + file.close; + }); + }); + if(cuedSeek, {pSeq = pSeq.add([seq, ledger.size - 1])}); + patterns = genPatterns.value(pSeq, addr); + player = Pfset(pattern: patterns, cleanupFunc: { + addr.sendMsg("/transport", 0); + }); + player = player.play + }); +}, \transport); + +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms; + noHarms = 30; + exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01); + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + +( +SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur; + var trig, exc, sig1, sig2, noHarms, freqFinal, start, end; + noHarms = 30; + freq = WhiteNoise.ar * 3 + freq; + freqFinal = Duty.ar((1/freq), 0, freq); + trig = Changed.ar(freqFinal); + start = Demand.ar(trig, 0, Dwhite(-1, -0.75)); + end = Demand.ar(trig, 0, Dwhite(0.75, 1)); + exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01); + + sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq), + Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}), + Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip; + sig1 = HPF.ar(sig1, 300); + Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2)); +}).add; +) + + + +"{\"a\": 1}".parseYAML["a"].asInteger; +"{\"a\": 1}".parseJSON["a"].isNumber; + +1223423434123.asHexString.toLower + +Date.getDate.rawSeconds +Date.seed.asHexString.toLower + +n = NetAddr("localhost", 8080); +n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals"); \ No newline at end of file diff --git a/supercollider/seeds_and_ledgers_transcriber.scd b/supercollider/seeds_and_ledgers_transcriber.scd new file mode 100644 index 0000000..4288a42 --- /dev/null +++ b/supercollider/seeds_and_ledgers_transcriber.scd @@ -0,0 +1,324 @@ +( +var formatMusicData, spellingDict, lyNoteNameStr, lyOctStr, lyFinalizeMusic, lyMeasureDef, +lyRelMark, lyRelMarkNote, lyHBracket, lyStaffDef, lyTie, +lyNoteName, lyCentDev, lyFreqRatio, lyDur, lyNote, lyBeamOpen, lyBeamClosed, +consolidateNotes, consolidateRests, +primes, hsArrayToFreq, hsArraysToFreqRatio; + +primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]]; + +hsArrayToFreq = { + arg array; + array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product +}; + +hsArraysToFreqRatio = { + arg array1, array2; + var fArray, num, den, gcd; + fArray = array2 - array1; + num = 1; + den = 1; + fArray.do({arg dim, d; + if(dim > 0, { + num = num * pow(primes[d][0], dim.abs); + den = den * pow(primes[d][1], dim.abs); + }); + if(dim < 0, { + num = num * pow(primes[d][1], dim.abs); + den = den * pow(primes[d][0], dim.abs); + }); + }); + gcd = gcd(num.asInteger, den.asInteger); + [num / gcd, den / gcd].asInteger +}; + +// formats the data for the transcriber +formatMusicData = {arg seq; + var maxSize, voices, durs, baseData, musicData; + maxSize = 0; + # voices, durs = seq.flatten2(seq.maxDepth - 5).flop; + + baseData = voices.flop.collect({arg voice, v; + var clumps, hdScores, freqs, fDurs, refs; + + //this gets the reference instrument and is another way to check things + refs = voice.collect({arg item, i; + var ref = [-1, [1, 1]]; + if((i > 0), { + if((item != voice[i - 1]) && (item != ["Rest"]), { + var ins; + ins = voices[i].minIndex({arg hsArray, h; + var res = 100000; + if((h != v) && (hsArray != ["Rest"]), {res = (hsArray.drop(1) - item.drop(1)).abs.sum}); + res + }); + if(voices[i][ins] != ["Rest"], { + ref = [ins, hsArraysToFreqRatio.value(voices[i][ins], item)] + }, { + ref = [ins, [100, 100]] + }) + }); + }); + ref + }); + + clumps = voice.separate({arg a, b; a != b }); + freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))/*.cpsmidi.round(0.25).midicps*/}, {-1})}); + fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum}); + refs = refs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump[0]}); + [freqs, (fDurs / 0.125).round, refs].flop; + }); + + musicData = baseData.collect({arg partData, p; + var res; + res = partData.collect({arg item, i; + var freq, dur, ref, amp, sus, note; + //# freq, dur, amp, mult, insRef = item; + # freq, dur, ref = item; + sus = dur.asInteger; + note = sus.collect({[freq, ref, i]}); + //rest = if(p < rawMusicData.size, {(dur - sus).collect({[-1, -1, -1, i]})}, {[]}); + //note ++ rest + note + }).flatten; + if(res.size > maxSize, {maxSize = res.size}); + res + }); + + //make them all the same length + maxSize = maxSize.trunc(64) + 64; + musicData = musicData.collect({arg partData, p; partData.extend(maxSize, partData.last)}); + musicData +}; + +// constants (spelling dictionary note names and octaves) +spellingDict = Dictionary.with(* + [ + \major -> Dictionary.with(* + [0, 7, 2, 9, 4, 11].collect({arg pc; pc->\sharps}) ++ + [5, 10, 3, 8, 1, 6].collect({arg pc; pc->\flats}) + ), + \minor -> Dictionary.with(* + [9, 4, 11, 6, 1, 8].collect({arg pc; pc->\sharps}) ++ + [2, 7, 0, 5, 10, 3].collect({arg pc; pc->\flats}) + ) + ] +); + +//define staff +lyStaffDef = {arg name, nameShort, nameMidi; + "\\new Staff = \"" ++ name ++ "\" \\with { \n" ++ + "instrumentName = \"" ++ name ++ "\" \n" ++ + "shortInstrumentName = \"" ++ nameShort ++ "\" \n" ++ + "midiInstrument = #\"" ++ nameMidi ++ "\" \n" ++ + "\n}\n" +}; + +// add music preamble +lyFinalizeMusic = {arg lyStr, part, name, nameShort, nameMidi, clef; + "\\new StaffGroup \\with {\\remove \"System_start_delimiter_engraver\"}\n<<\n" ++ + lyStaffDef.value(name, nameShort, nameMidi) ++ + "<<\n\n{ " + + "\n\\set Score.markFormatter = #format-mark-box-numbers " + + "\\tempo 2 = 60\n" + + "\\numericTimeSignature \\time 2/2\n" + + "\\clef " ++ clef ++ "\n" ++ lyStr + "\\fermata" + + " }>> \\bar \"|.\" \n} \n\n>>" ++ + "\n>>" +}; + +// barline and ossia definition +lyMeasureDef = {arg insName, part, beat; + var barline = "|", break = ""; + barline = "\\bar \"|\""; + if((beat % 16) == 0, {break = "\\break \\noPageBreak"}); + if((beat % (16 * 3)) == 0, {break = "\\pageBreak"}); + if(beat != 0, {"}\n>>\n" + barline + break}, {""}) + "\n<<\n" /*++ ossia*/ + "{" +}; + +lyNoteNameStr = Dictionary.with(* + [ + \sharps -> ["c", "cis", "d", "dis","e", "f", "fis", "g", "gis", "a", "ais", "b"], + \flats -> ["c", "des", "d", "ees","e", "f", "ges", "g", "aes", "a", "bes", "b"], + ] +); + +lyOctStr = [",,", ",", "", "'", "''", "'''", "''''"]; + +lyTie = {"~"}; + +lyNoteName = {arg freq, spellingPref = \sharps; + if(freq != -1, { + lyNoteNameStr[spellingPref][((freq.cpsmidi).round(1) % 12)] ++ + lyOctStr[(((freq).cpsmidi).round(1) / 12).asInteger - 2]; + },{"r"}); +}; + +lyDur = {arg noteLength; + switch(noteLength, 1, {"16"}, 2, {"8"}, 3, {"8."}, 4, {"4"}); +}; + +lyBeamOpen = {"["}; + +lyBeamClosed = {"]"}; + +lyCentDev = {arg freq, padding = true; + var centDev; + centDev = ((freq.cpsmidi - (freq.cpsmidi).round(1)) * 100).round(1).asInteger; + "^\\markup { " ++ if(padding, {"\\pad-markup #0.2 \""}, {"\""}) ++ + if(centDev >= 0, {"+"}, {""}) ++ centDev.asString ++ "\"}" +}; + +lyFreqRatio = {arg freqRatioMult, ref, padding = true, lower = 3, attachedToNote = true; + var res, ratio; + res = "\\markup {" + if(attachedToNote, {""}, {"\\normalsize"}) + + "\\lower #" ++ lower + if(padding, {"\\pad-markup #0.2 "}, {" "}); + ratio = "\"" ++ freqRatioMult[0].asInteger ++ "/" ++ freqRatioMult[1].asInteger ++ "\" }"; + res = if(ref != nil, + { + res ++ "\\concat{ \"" ++ ["IV", "III", "II", "I"][ref] ++ "\"\\normal-size-super " ++ ratio ++ "}" + }, { + res ++ ratio + } + ); + if(attachedToNote, {"_" ++ res}, {res}) +}; + +lyNote = {arg freq, noteLength, freqRatioMult, ref, spellingPref = \sharps, addMarkup = true, frHide = false, padding = true; + lyNoteName.value(freq, spellingPref) ++ + lyDur.value(noteLength) ++ + if(addMarkup, { + "" + }, {""}) +}; + +consolidateNotes = {arg lyStr, part; + var noteRegex, markupRegex, fullNoteRegex, restRegex, fullRestRegex, res; + noteRegex = "(?[a-g](?:es|is)?(?:[,']*?)?4)"; + markupRegex = if(part != 0, {"()?"}, {"()?"}); + fullNoteRegex = noteRegex ++ markupRegex ++ "(?:\\h+~\\h+\\k)"; + restRegex = "(?r4)"; + fullRestRegex = "(?r4)(?:(\\h+)\\k)"; + res = lyStr; + [6, 4, 3, 2].do({arg len; + [fullNoteRegex, fullRestRegex].do({arg regex; + res.findRegexp(regex ++ "{" ++ (len-1) ++ "}").clump(3).do({arg match; + var word, note, markup, lyDur; + word = match[0][1]; + note = match[1][1]; + markup = match[2][1]; + lyDur = switch(len, 6, {"1."}, 4, {"1"}, 3, {"2."}, 2, {"2"}); + res = res.replace(word, note.replace("4", lyDur) ++ markup)}); + }); + }); + res.replace("", ""); +}; + +~transcribe = {arg rawMusicData; + var basePath, scoreFile, musicData, insData, insNames, insNamesShort, insMidi, insClef; + + basePath = thisProcess.nowExecutingPath.dirname +/+ "lilypond"; + basePath.mkdir; + (basePath +/+ "includes").mkdir; + + //scoreFile = File(basePath +/+ "tkam_score.ly".standardizePath,"w"); + //scoreFile.write(File.readAllString(basePath +/+ ".." +/+ "template" +/+ "tkam_score_template.ly").replace("seed: xxx", "seed: " ++ seed)); + //scoreFile.close; + + musicData = formatMusicData.value(rawMusicData); + + insData = [ + ["IV", "IV", "clarinet", "bass"], + ["III", "III", "clarinet", "alto"], + ["II", "II", "clarinet", "treble"], + ["I", "I", "clarinet", "treble"] + ]; + + insNames = insData.slice(nil, 0); + insNamesShort = insData.slice(nil, 1); + insMidi = insData.slice(nil, 2); + insClef = insData.slice(nil, 3); + + musicData.do({arg part, p; + var lyFile, lyStr, lastMusAtom, measureCount, spellingPref, + tmpSectionData, pcRoot, partLookup, quality; + + //create file + lyFile = File((basePath +/+ "includes" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly").standardizePath,"w"); + + //start lypond directives + lyStr = ""; + lastMusAtom = nil; + measureCount = 0; + spellingPref = \sharps; + tmpSectionData = nil; + part.clump(4).do({arg beat, i; + var gSum; + gSum = 0; + beat.separate({arg a, b; + ((a[0] != -1) || (b[0] != -1)) && (a != b)}).do({arg group, g; + var noteLength, curMusAtom, freq, freqRatioMult, ref, isSame, isRest, isFirst, isLast, + isTied, isMeasureBound, isBeamStart, isBeamEnd; + + noteLength = group.size; + gSum = gSum + noteLength; + curMusAtom = group[0]; + freq = curMusAtom[0]; + //freqRatioMult = curMusAtom[1]; + ref = curMusAtom[1][0]; + freqRatioMult = curMusAtom[1][1]; + # isSame, isRest, isFirst, isLast = [curMusAtom == lastMusAtom, freq == -1, g == 0, gSum == 4]; + # isTied, isMeasureBound = [isSame && isRest.not, isFirst && ((i % 4) == 0)]; + # isBeamStart, isBeamEnd = [(noteLength != 4) && isFirst, (noteLength != 4) && isLast]; + + //add ties + if(isTied, {lyStr = lyStr + lyTie.value}); + + //add barline and ossia definition + //if(isMeasureBound, {lyStr = lyStr + "\\bar \"|.|\""}); //lyMeasureDef.value(sectionData[i], insNames[p], p, i)}); + if(isMeasureBound, {lyStr = lyStr + lyMeasureDef.value(insNames[p], p, i)}); + + //add note data + /* + if(sectionData[i] != nil, { + tmpSectionData = sectionData[i]; + }); + if(isTied.not, { + partLookup = if((p != 0) || [1, 2, 3].includes(ref).not , {p}, {ref}); + pcRoot = ((tmpSectionData[0][partLookup][3].cpsmidi).round(1) % 12).asInteger; + quality = if(tmpSectionData[0][partLookup][1][2] == [[ 1, 5 ], [ 1, 2, 2 ]], {\major}, {\minor}); + spellingPref = spellingDict[quality][pcRoot]; + if(p == 0, {[(i / 4).asInteger, partLookup, pcRoot, quality]}); + }); + */ + + //lyStr = lyStr + lyNote.value(freq, noteLength, freqRatioMult, ref, spellingPref, isSame.not && isRest.not); + lyStr = lyStr + lyNote.value(freq, noteLength, freqRatioMult, ref, \sharps, isSame.not && isRest.not); + + //beam group + if(isBeamStart, {lyStr = lyStr ++ lyBeamOpen.value}); + if(isBeamEnd, {lyStr = lyStr ++ lyBeamClosed.value}); + + lastMusAtom = curMusAtom; + }); + }); + + //wrap music and add staff definitions + lyStr = lyFinalizeMusic.value(lyStr, p, insNames[p], insNamesShort[p], insMidi[p], insClef[p]); + + //consolidate notes and rests + lyStr = consolidateNotes.value(lyStr, p); + + //write file + lyFile.write(lyStr); + lyFile.close; + }); +}; + + +~transcribe.value(~seq); + +) \ No newline at end of file