]> git.dabkitsch.com - m29-web-sfp.git/commitdiff
updated to a rev1 status; most features in place for loading, editing, and saving. v1.0
authorequilet <2237372+equilet@users.noreply.github.com>
Tue, 13 Aug 2024 21:15:07 +0000 (14:15 -0700)
committerequilet <2237372+equilet@users.noreply.github.com>
Tue, 13 Aug 2024 21:15:07 +0000 (14:15 -0700)
app.js
index.html
style/style.css

diff --git a/app.js b/app.js
index 921806668f04a1d508c8bfbe39a603e94a0f96bc..8ccfaa3321df46645ee63f00da71e2b672a2aff3 100644 (file)
--- a/app.js
+++ b/app.js
@@ -1,8 +1,8 @@
 const num_storage_slots = 16;
-let num_regions = 0;
-let filepath = "media/Berio-criesoflondon.wav";
+const skip_factor = 0.5;
+let num_regions = 1;
 let global_dict = new Object();
-let active_region = null;
+let active_region, was_clicked = null;
 let global_dur = 3.0;
 let text_input, text_butt, timevalues;
 let btn_r = [];
@@ -10,8 +10,8 @@ let btn_tp = [];
 let btn_misc = [];
 let ws;
 let wsr;
-let looping = false;
-
+let sep_window;
+let looping, in_region;
 
 //initialization---------------------------------------------------------------------
 //
@@ -40,7 +40,31 @@ document.addEventListener('DOMContentLoaded', function(){
     //fs.writeFile();
 //}
 
-function cue_select(i) {
+function open_window() {
+    const window_features = "height=200,width=400,status=yes,toolbar=no,menubar=no,location=no";
+    sep_window = window.open("", null, window_features);
+
+    if(!sep_window) {
+        console.error("window cannot be opened.");
+        return;    
+    }
+
+    sep_window.document.write(`
+        <!DOCTYPE html>
+        <html lang="en">
+        <head>
+            <meta charset="UTF-8">
+            <meta name="viewport" content="width=device-width, initial scale=1.0">
+            <title>Text Window</title>
+        </head>
+        <body>
+            <p id="text_element">initial text</p>
+        </body>
+        </html>
+    `);
+}
+
+function cue_region(i) {
     const all_regions = wsr.getRegions();
     active_region = all_regions[i];
     active_region.play();
@@ -59,6 +83,23 @@ function linear_map(phase, imn, imx, omn, omx) {
     return (phase - imn) * (omx - omn) / (imx - imn) + omn;
 }
 
+function add_region_specified(tstart, tend, ttext, id, tcolor) {
+
+    num_regions++;
+
+    wsr.addRegion({
+        channelIdx: id,
+        content: ttext,
+        id: 'region',
+        start: tstart,
+        end: tend,
+        loop: false,
+        //color: 'hsla(' + gen_color() + ', 100%, 50%, 0.1)'
+        color: tcolor
+    });
+
+}
+
 function add_1_region() {
 
     const gen = gen_region_startend();
@@ -66,8 +107,8 @@ function add_1_region() {
     //console.log("adding a region with id", num_regions);
 
     wsr.addRegion({
-        channelIdx: num_regions + 1
-        content: "region" + num_regions + "text",
+        channelIdx: num_regions, 
+        content: "region" + (num_regions - 1) + "text",
         id: 'region',
         start: gen[0], 
         end: gen[1], 
@@ -77,27 +118,28 @@ function add_1_region() {
 
 }
 
-function add_3_regions() {
-    let percent_hue = new Number();
-
+function gen_color() {
+    return Math.floor(Math.random() * 100.0);
+}
 
+function add_3_regions() {
+    //let percent_hue = new Number();
     for(let i = 1; i < 4; i++){
 
         const gen = gen_region_startend();
-        //let percent_lum = Math.random() * 100.0;
-        percent_hue = Math.floor(Math.random() * 100.0);
-        //const test_string = 'hsla(' + percent_hue + ', 100%, 50%, 0.1)';
         num_regions++;
+        //percent_hue = Math.floor(Math.random() * 100.0);
 
+        //console.log("adding a region with id", num_regions);
         wsr.addRegion({
-            channelIdx: num_regions + 1,
-            content: "region" + num_regions + "text",
+            channelIdx: num_regions,
+            content: "region" + (num_regions - 1) + "text",
             id: 'region',
             start: gen[0], 
             end: gen[1], 
             loop: false, 
            // color: 'hsla(' + percent_hue + '%, 100%, 50%, 0.1)'
-            color: 'hsla(' + percent_hue + ', 100%, 50%, 0.1)'
+            color: 'hsla(' + gen_color() + ', 100%, 50%, 0.1)'
         });
 
     }
@@ -108,11 +150,12 @@ function add_region_at_time(time){
     //const percent_lum = Math.random() * 100.0;
     let percent_hue = Math.floor(Math.random() * 100.0);
     const test_string = 'hsla(' + percent_hue + ', 100%, 50%, 0.1)';
-    console.log("test string: ", test_string);
+
+    //console.log("adding a region with id", num_regions);
 
     wsr.addRegion({
-        channelIdx: num_regions + 1
-        content: "region" + num_regions + "text",
+        channelIdx: num_regions, 
+        content: "region" + (num_regions - 1) + "text",
         //id: "cue " + i, 
         id: 'region',
         start: time, 
@@ -135,92 +178,186 @@ function gen_region_startend(){
 
 function clear_regions() {
     wsr.clearRegions();
-    num_regions = 0;
+    num_regions = 1;
 }
 
 function buttons_reset() {
         btn_tp_reset();
         btn_r_reset();
         btn_m_reset();
-        //marker_view_reset();
 }
 
-function marker_view_reset(){
-    //curr_region = null;
+function region_view_reset(){
     active_region = null;
-    text_input.value = "no marker selected";
+    text_update("<no region active>");
+}
+
+function text_update(text_string) {
+    //this updates the separated window
+    text_input.value = text_string;
+
+    if(sep_window) {
+        let sep_text = sep_window.document.getElementById('text_element');
+        sep_text.textContent = text_string;
+    }
+}
+
+function text_transfer() {
+    //this does not update the separated window
+    if(active_region != null){
+        console.log("found active region; populating...");
+        active_region.content.innerHTML = text_input.value;
+    }
 }
 
+/*
+function advance_region(direction){
+    if(active_region === null){
+        return;
+    }
+
+    if(direction == 1){
+        active_region++;
+
+    }else if(direction == -1){
+        active_region--;
+    }
+}
+*/
+
 //-------------------------------------------------------------
-//https://medium.com/analytics-vidhya/local-storage-with-vanilla-javascript-c87e3923163a
+//file read/write/clear/etc-----------------------------------------
 //
 
-//localStorage read/write/clear/etc
+function json_load(json) {
+    //console.log("inside load json func");
+    
+    if(!wsr){
+        console.error("No wsr variable initialized...  aborting.");
+        return;
+    }
+    clear_regions(); 
+    let tregion = [];
+    let ttext, tid, tcolor;
+
+    for(const key in json){
+        //console.log(`${key}: ${json[key]}`);
+        tregion = json[key].region;
+        ttext = json[key].text;
+        tid = json[key].id;
+        tcolor = json[key].color;
+
+        //tstart, tend, text, id, tcolor
+        add_region_specified(tregion[0], tregion[1], ttext, tid, tcolor);
+        //console.log("key: ", key, 'value: ', global_dict[key]);
+    }
+}
+
+//gather and write json from existing user program
+//this is a local save
+function json_save() {
+    
+    //save data into LS for next use by user (if cache is not cleared)
+    const all_regions = wsr.getRegions(); 
+    let id = -1;
+    localStorage.clear();
+    var json_object = {};
+
+    all_regions.forEach(function (region) {
+        id = region.channelIdx; 
+
+        //const txt = '[' + region.start + ', ' + region.end + ', ' + region.content.innerHTML + ', ' + id + ', ' + region.color + ']';
+        //localStorage.setItem("r" + id, txt);
+        
+        localStorage.setItem("r" + id + "-id", region.channelIdx);
+        localStorage.setItem("r" + id + "-content", region.content.innerHTML);
+        localStorage.setItem("r" + id + "-start", region.start);
+        localStorage.setItem("r" + id + "-end", region.end);
+        localStorage.setItem("r" + id + "-color", region.color);
+        
+        const json_region = {};
+
+        json_region.region = [region.start, region.end];
+        json_region.text = region.content.innerHTML;
+        json_region.id = id;
+        json_region.color = region.color;
+
+        json_object["r" + id] = json_region;
+    });
+
+        //const key = localStorage.key(i);
+        //json_object[key] = localStorage.getItem(key);
+    
+
+    const sorted_keys = Object.keys(json_object).sort((a, b) => a.localeCompare(b, undefined, { numeric: true } ));
+    const sorted_json = {};
+    sorted_keys.forEach(key => {
+        sorted_json[key] = json_object[key];
+    });
+
+    const json_string = JSON.stringify(sorted_json, null, 2); //format with indentation
+
+    //we generate the [save] button during initialize()
+    document.getElementById('save').addEventListener('click', () => {
+        //const textcontent = "this is a test written in the application by jml";
+        //const blob = new Blob([textcontent], { type: 'text/plain' });
+        const blob = new Blob([json_string], { type: 'application/json' });
+        const url = URL.createObjectURL(blob);
+        const a = document.createElement('a');
+
+        a.href = url;
+        a.download = 'sfp_data.json';
+        a.click();
+        URL.revokeObjectURL(url);
+    });
+
+}
+
+//https://medium.com/analytics-vidhya/local-storage-with-vanilla-javascript-c87e3923163a
+//
 function localstorage_post() {
     console.log(JSON.stringify(localStorage));
 }
 
+//-------------------------------------------------------------
 //NOTE: does not upload any audio files.  
 //Audio is exclusively contained to your local machine, and is populated via drag-and-drop operation
-function file_write_to_server() {}
-function file_read_from_server() {}
+//
 
-function localstorage_write() {
-    const all_regions = wsr.getRegions(); 
-    
-    all_regions.forEach(function (region) {
-        const key = region.channelIdx;
-        const value = region.content;
-        localStorage.setItem(key, value);
-        console.log("storing", key, "with a value of", value);
-    });
+function localstorage_restore() {
 
-}
+    console.log("ls restore: reading localStorage...");
 
-function localstorage_read(file) {
-    //set num_regions var here
+    num_regions = 1;
     let inc = 0;
-    localStorage.clear();
-    //some sort of initialization for program needed here
-    const ls_json = JSON.stringify(localStorage);
+    clear_regions();
 
     for(var key in localStorage) {
-        let data = window.localStorage.getItem(key);
+        let data = localStorage.getItem(key);
         //set some local variable
+        console.log("key is: ", key);
+        console.log("data is: ", data);
         inc++;
     }
 
     num_regions = inc;
-
-    console.log("reading", ls_json);
-
-
 }
 
 //-------------------------------------------------------------
+//Initialization
 
-function initialize(){
-    
-    active_region = null;
+function audio_load(a_path) {
 
     ws = WaveSurfer.create({
         container: '#waveform',
-        waveColor: 'hsla(0, 0%, 12%, 0.8)',
-        progressColor: 'hsla(0, 0%, 25%, 0.5)',
-        url: filepath
-        /*
-        , plugins: [
-            WaveSurfer.Regions.create({})
-        ]
-        */
+        progressColor: 'rgb(150,150,150)',
+        waveColor: 'rgb(200,200,200)',
+        url: a_path
     });
 
-    //let RegionsPlugin = window.WaveSurfer.regions;
-    //wsr = window.WaveSurfer.regions;
     wsr = ws.registerPlugin(WaveSurfer.Regions.create())
 
     const wf = document.getElementById("waveform");
-
     //append a div for the display of percentage loaded
     const percent_elem = document.createElement("div");
     percent_elem.id = "percent";
@@ -228,12 +365,13 @@ function initialize(){
     wf.appendChild(percent_elem);
 
     ws.on('ready', function (){
+        text_update("<no region active>");
         console.log("wavesurfer ready.");
     });
 
     //put a text element over the ws while this is loading
     ws.on('loading', (percent) => {
-        //console.log('loading', percent, '%');
+        //console.log('inside of loading method...');
         if(percent < 100){
             percent_elem.innerHTML = `<h1>${percent}%</h2>`;
         } else {
@@ -244,18 +382,17 @@ function initialize(){
         }
 
     });
-
     ws.on('click', (relativeX) => {
+        in_region = false;
         ws.pause();
         ws.seekTo(relativeX);
         //ws.play();
         buttons_reset();
-        marker_view_reset();
+        region_view_reset();
     });
 
     ws.on('timeupdate', (currentTime) => {
-        let timestring = get_time_string(currentTime);
-
+        const timestring = get_time_string(currentTime);
         timevalues.innerHTML = timestring;
 
         //some floating point error here to deal with...
@@ -269,56 +406,253 @@ function initialize(){
         }
     });
 
-    /*
     wsr.on('region-updated', (region) => {
-        //console.log("a region with id", region.channelIdx, "was updated.");
-        //console.log("the new start:", region.start);
-        //console.log("the new end:", region.end);
+
+        in_region = true;
+        active_region = region;
+        buttons_reset();
+
+        text_update(region.content.innerHTML);
+
+        /*
+        console.log("a region with id", region.channelIdx, "was updated.");
+        console.log("the new start:", region.start);
+        console.log("the new end:", region.end);
         //do something here to update json or re-popuplate all marker data
+        */
     });
-    */
 
     wsr.on('region-clicked', (region, e) => {
+
         e.stopPropagation();
+        in_region = true;
         active_region = region;
-
-        //active_region.loop = looping;
-        active_region.play();
-        //this doesn't work as far as I can tell: region.play(region.start, region.end)
         buttons_reset();
-        text_input.value = region.content.innerHTML;
+        text_update(region.content.innerHTML);
+
+        //ws.pause();
+        ws.seekTo(region.start);
+
+        //e.startPropagation();
         console.log("----------------------------------------------------------");
         console.log("a region with id", region.channelIdx, "was clicked.");
         console.log("region range:", region.start, region.end);
-        //console.log("this region's text:", region.content.innerHTML);
+        console.log("this region's text:", region.content.innerHTML);
+    });
+
+    wsr.on('region-in', (region) => {
+        //buttons_reset();
+        //e.stopPropagation();
+        text_update(region.content.innerHTML);
     });
 
     wsr.on('region-out', (region) => {
+        //active_region = null;
+        text_update("<no region active>");
+    });
+
+    /*
+    wsr.on('region-out', (region, e) => {
+        //console.log("region-out detected from" + region.channelIdx + "...  try to implement a loop function here");
         //e.stopPropagation();
-        console.log("region-out detected from" + region.channelIdx + "...  try to implement a loop function here");
+
+        console.log("current time before seek:", ws.currentTime);
+        if (looping) {
+            region.play();
+        } else {
+            //ws.playPause();
+            ws.seekTo(region.start);
+            console.log("current time after seek:", ws.currentTime);
+            in_region = false;
+            //active_region = null;
+        }
     });
+    */
+}
+
+function initialize() {
+    
+    active_region = null;
+    in_region = false;
+
 
-    //key events -----------------------------------------------------------------
+    //keyboard events -----------------------------------------------------------
     //
 
     window.addEventListener("keydown", (e) => {
-        if(!e.repeat && e.key == 'm') {
-            //console.log('the m key was pressed'); 
-            //add_1_region();
-            add_region_at_time(ws.getCurrentTime());
-        } 
+        if(e.target.nodeName == "TEXTAREA") {
+            //do nothing; accept input as normal
+        } else {
+            //marker
+            if(!e.repeat && e.key == 'r') {
+                add_region_at_time(ws.getCurrentTime());
+                return;
+            } 
+
+            //this needs to be cleaned up w/r/t detection of cases....
+            //transport
+            if(!e.repeat && e.key == ' ') {
+                if(in_region) {
+                    active_region.play();
+                } else {
+                    ws.playPause();
+
+                }
+                return;
+            }
+            if(!e.repeat && e.key == 'ArrowLeft') {
+                if(!in_region) {
+                    ws.skip(-skip_factor);
+                }
+                return;
+            }
+            if(!e.repeat && e.key == 'ArrowRight') {
+                if(!in_region) {
+                    ws.skip(skip_factor);
+                }
+                return;
+            }
+            //focus textarea
+            if(!e.repeat && e.key == 'e') {
+                e.preventDefault();
+                text_input.focus();        
+                return;
+            }
+        }
+    });
+
+    //json file loading mechanism
+    document.getElementById('file_input_json').addEventListener('change', function(ev) {
+        const file = ev.target.files[0];
+        console.log('attempting to load JSON: ', file);
+        if(file) {
+            const reader = new FileReader();
+            reader.onload = function(e) {
+                try {
+                    const content = e.target.result;
+                    const json_content = JSON.parse(content);
+                    json_load(json_content);
+                    /*
+                    const postable = JSON.stringify(json_content, null, 2);
+                    console.log("file load post: ", postable);
+                    */
+                } catch(error) {
+                    console.error("error parsing json: ", error.message); 
+                }
+            }
+
+            reader.readAsText(file);
+        }
+    });
+    //audio file loading mechanism
+    document.getElementById('file_input_audio').addEventListener('change', function(ev) {
+
+        const file = ev.target.files[0];
+        console.log('attempting to load audio: ', file);
+
+        if(file) {
+            const file_info = `
+                File name: ${file.name}
+                File size: ${file.size} bytes
+                File type: ${file.type}
+                Last Modified: ${new Date(file.lastModified).toLocaleString()}
+            `;
+
+            console.log("file info", file_info);
+            const audio_URL = URL.createObjectURL(file);
+            console.log("url info: ", audio_URL);
+            audio_load(audio_URL);
+        }
+    });
+
+    document.addEventListener('click', (e) => {
+        const selection = window.getSelection();
+        const clicked_elem = e.target.id;
+
+        if(e.target.id == 'textinput') {
+            //do nothing; maybe highlight or colorize?
+        } else if(was_clicked == 'textinput') {
+            //console.log('user clicked outside of text box, and last clicked was text box');
+            text_transfer();
+        }
+        was_clicked = clicked_elem;
     });
 
     //user data ------------------------------------------------------------------
     //
+    const brk = "\n -------------";
+    const ed_cr = brk + brk + brk + "\n";
     
     global_dict = {
-        "soundfile" : filepath,
-        "m0" : [2.4, 3., "m1 label"], 
-        "m1" : [8.2, 3., "m2 label"], 
-        "m2" : [11.7, 3., "m3 label"], 
-        "m3" : [14.9, 3., "m4 label"]
-    };
+        "r2": {
+            "region": [0.07652782486802312, 1.464475134610756],
+            "text": "gesture A1\n -------------\n -------------\n -------------\nNotice how the gesture rises in pitch",
+            "id": 2,
+            "color": "hsla(0, 100%, 50%, 0.1)"
+        },
+        "r3": {
+            "region": [1.8692600113275684, 3.195274968850553],
+            "text": "gesture A2",
+            "id": 3,
+            "color": "hsla(20, 100%, 50%, 0.1)"
+        },
+        "r4": {
+            "region": [3.6112875615251694, 5.12028059605844],
+            "text": "gesture A3\n -------------\n -------------\n -------------\neach repeat of gesture A is slightly varied in duration and energy",
+            "id": 4,
+            "color": "hsla(40, 100%, 50%, 0.1)"
+        },
+        "r5": {
+            "region": [5.354219, 6.6800804962279035],
+            "text": "gesture A4",
+            "id": 5,
+            "color": "hsla(60, 100%, 50%, 0.1)"
+        },
+        "r6": {
+            "region": [7.11208, 8.456021562101203],
+            "text": "gesture A5",
+            "id": 6,
+            "color": "hsla(80, 100%, 50%, 0.1)"
+        },
+        "r7": {
+            "region": [8.869941, 10.167390964141314],
+            "text": "gesture A6",
+            "id": 7,
+            "color": "hsla(100, 100%, 50%, 0.1)"
+        },
+        "r8": {
+            "region": [10.547167, 11.990076448815238],
+            "text": "gesture A7",
+            "id": 8,
+            "color": "hsla(120, 100%, 50%, 0.1)"
+        },
+        "r9": {
+            "region": [12.288901, 13.583264123626352],
+            "text": "gesture A8",
+            "id": 9,
+            "color": "hsla(140, 100%, 50%, 0.1)"
+        },
+        "r10": {
+            "region": [13.966126, 21.307924676142115],
+            "text": "gesture B: New long phrase B.  Notice how the performer softens the energy and allows the closing of the 12-bar cycle",
+            "id": 10,
+            "color": "hsla(180, 100%, 50%, 0.1)"
+        }
+    }
+
+        /*
+        //"soundfile" : filepath,
+        //<start> <end> <textstring> <id> <colorstr>
+        "r0" : [0.07652782486802312, 1.464475134610756, "gesture A1" + ed_cr + "Notice how the gesture rises in pitch", 2, "hsla(0, 100%, 50%, 0.1)"], 
+        "r1" : [1.8692600113275684, 3.195274968850553, "gesture A2", 3, "hsla(20, 100%, 50%, 0.1)"], 
+        "r2" : [3.6112875615251694, 5.12028059605844, "gesture A3" + ed_cr + "each repeat of gesture A is slightly varied in duration and energy", 4, "hsla(40, 100%, 50%, 0.1)"],
+        "r3" : [5.354219, 6.6800804962279035, "gesture A4", 5, "hsla(60, 100%, 50%, 0.1)"], 
+        "r4" : [7.11208, 8.456021562101203, "gesture A5", 6, "hsla(80, 100%, 50%, 0.1)"],
+        "r5" : [8.869941, 10.167390964141314, "gesture A6", 7, "hsla(100, 100%, 50%, 0.1)"],
+        "r6" : [10.547167, 11.990076448815238, "gesture A7", 8, "hsla(120, 100%, 50%, 0.1)"],
+        "r7" : [12.288901, 13.583264123626352, "gesture A8", 9, "hsla(140, 100%, 50%, 0.1)"],
+        "r8" : [13.966126, 21.307924676142115, "gesture B: New long phrase B.  Notice how the performer softens the energy and allows the closing of the 12-bar cycle", 10, "hsla(180, 100%, 50%, 0.1)"]
+        */
 
     //interface data--------------------------------------------------------------
     //
@@ -331,9 +665,8 @@ function initialize(){
             clicked: false, 
             call_action: function(){
                 btn_r_reset();
-                cue_select(i);
-                //console.log('recall button', i, 'clicked');
-
+                cue_region(i);
+                console.log('recall button', i, 'clicked');
             },
         };
         btn_r.push(temp);
@@ -345,8 +678,12 @@ function initialize(){
             text: "play/resume",
             clicked: false,
             call_action: function () {
-                ws.play();
-            },
+                if(in_region){
+                    active_region.play();
+                } else {
+                    ws.play();
+                }
+            }
         },
         {
             id: "pause",
@@ -354,7 +691,15 @@ function initialize(){
             clicked: false,
             call_action: function () {
                 ws.pause();
-            },
+            }
+        },
+        {
+            id: "rw",
+            text: "<<", 
+            clicked: false, 
+            call_action: function () {
+                ws.skip(-skip_factor);
+            }
         },
         {
             id: "stop",
@@ -362,8 +707,17 @@ function initialize(){
             clicked: false,
             call_action: function () {
                 ws.stop();
-            },
-        }
+                this.clicked = false;
+            }
+        }, 
+        {
+            id: "ff", 
+            text: ">>",
+            clicked: false, 
+            call_action: function () {
+                ws.skip(skip_factor);
+            }
+        } 
     ];
 
     btn_misc = [
@@ -381,7 +735,7 @@ function initialize(){
 
         {
             id: "clear",
-            text: "clear markers", 
+            text: "clear regions", 
             clicked: false, 
             call_action: function () {
                 clear_regions();
@@ -389,7 +743,7 @@ function initialize(){
         }, 
         {
             id: "genN",
-            text: "generate markers",
+            text: "generate regions",
             clicked: false,
             call_action: function () {
                 add_3_regions();
@@ -397,19 +751,57 @@ function initialize(){
         }, 
         {
             id: "gen1", 
-            text: "generate 1 marker", 
+            text: "generate 1 region", 
             clicked: false, 
             call_action: function () {
                 add_1_region();
             }
         }, 
+        /*
+        {
+            id: "load", 
+            text: "load default data",
+            clicked: false,
+            call_action: function () {
+                console.log('currently unimplemented');
+                //const default_path_audio = "media/Music29_Little_Walter_Blues.wav";
+                //const default_path_json = "media/initdata.json";
+                //audio_load(default_path_audio);
+                //json_load(default_path_json);
+            }
+        },
+        */
+        {
+            id: "loadfile",
+            text: "load JSON file", 
+            clicked: false,
+            call_action: function () {
+                document.getElementById('file_input_json').click(); 
+            }
+        },
+        {
+            id: "loadsound", 
+            text: "load sound file",
+            clicked: false,
+            call_action: function () {
+                document.getElementById('file_input_audio').click();
+            }
+        },
         {
             id: "save", 
-            text: "save your work",
+            text: "save data",
             clicked: false,
             call_action: function () {
-                localstorage_write();
-            },
+                json_save();
+            }
+        },
+        {
+            id: "openwind", 
+            text: "open window",
+            clicked: false,
+            call_action: function () {
+                open_window();
+            }
         }
     ];
 }
@@ -474,16 +866,32 @@ function buttons_make() {
         button_elem.classList.add("buttons");
         button_elem.innerHTML = `<h2>${button.text}</h2>`;
 
-        button_elem.addEventListener("click", () => {
-
-            if (!button.clicked) {
-                btn_tp_reset();
-                button.clicked = true;
-                button.call_action();
-                button_elem.classList.add("clicked");
-            }
-
-        });
+        if(button_elem.id === "ff" | button_elem.id === "rw"){
+            button_elem.addEventListener("mousedown", () => {
+                if (!button.clicked) {
+                    btn_tp_reset();
+                    button.clicked = true;
+                    button.call_action();
+                    button_elem.classList.add("clicked");
+                }
+            });
+
+            button_elem.addEventListener("mouseup", () => {
+                if (button.clicked) {
+                    button.clicked = false;
+                    button_elem.classList.remove("clicked");
+                }
+            });
+        } else {
+            button_elem.addEventListener("click", () => {
+                if (!button.clicked) {
+                    btn_tp_reset();
+                    button.clicked = true;
+                    button.call_action();
+                    button_elem.classList.add("clicked");
+                }
+            });
+        }
 
         cont_tp.appendChild(button_elem);
     });
@@ -492,11 +900,11 @@ function buttons_make() {
     timedisp.id = "timedisp";
     timedisp.clicked = false;
     timedisp.classList.add("buttons");
-    timedisp.innerHTML = '<h2>00:00:00</h2>';
+    timedisp.innerHTML = '<h2>0:0:0</h2>';
     timevalues = timedisp.firstChild;
     cont_tp.appendChild(timedisp);
 
-    //cue marker area -----------------------------------------------------
+    //cue region area -----------------------------------------------------
     btn_r.forEach((button) => {
 
         const button_elem = document.createElement("div");
@@ -537,23 +945,28 @@ function buttons_make() {
                 button_elem.classList.add("clicked");
             }
         });
+
         button_elem.addEventListener("mouseup", () => {
             if (button.clicked) {
                 button.clicked = false;
                 button_elem.classList.remove("clicked");
             }
         });
+
         cont_misc.appendChild(button_elem);
     });
 
+    
+
     //region properties
     const check = document.getElementById("loop");
 
-    //marker interactions
+    //region interactions
     text_input = document.getElementById("textinput");
     text_butt = document.getElementById("textsubmit");
 
     check.addEventListener('change', (e) => {
+        
         if(e.target.checked) {
             looping = true;
             //console.log("check is positive");
@@ -561,23 +974,57 @@ function buttons_make() {
             looping = false;
             //console.log("check is negative");
         }
+        document.activeElement = null;
     });
 
-    //marker text
+    //region text
+    
+    /*
+    window.onkeydown(function(e) {
+        if(e.target.nodeName == 'INPUT' || e.target.nodename == 'TEXTAREA') {
+            return;
+        }
+        if(e.target.isContentEditable) {
+            return;
+        }
+
+        console.log("caught");
+    });
+    */
+
     text_butt.addEventListener('mousedown', () => {
 
         console.log("the text entered was", text_input.value);
-
-        if(active_region != null){
-            console.log("found active region; populating...");
-            active_region.content.innerHTML = text_input.value;
-        }
-        
+        text_transfer();
         text_butt.classList.add('clicked');
     });
 
     text_butt.addEventListener('mouseup', () => {
         text_butt.classList.remove('clicked');    
     });
+}
 
+/*
+//this was here for a case where user drops an audio file on page...
+function dropHandler(e) {
+   e.preventDefault();
+   console.log("file dropped to drop area");
+
+    if(e.dataTransfer.items) {
+        [...e.dataTransfer.items].forEach((item, i) => {
+            if(item.kind === 'file') {
+                //const file = item.getAsFile();
+                //console.log(`... file[${i}].name = ${file.name}`);
+                console.log("filename: ", file.name);
+            }
+        });
+    } else {
+        [...e.dataTransfer.files].forEach((file, i) => { 
+            //console.log(`... file[${i}].name = ${file.name}`);
+            console.log("filename: ", file.name);
+        });
+    }
 }
+*/
+
+
index da356437aae3c19ac2df8e07d74fec27da748154..560268e39ee43a51dcd3bd634924f85e37f3c12f 100644 (file)
 
         <div id="waveform">
         </div>
-        <div id="droparea">
-        </div>
 
         <div id="marker_edit">
             <h2>Edit Marker</h2>
             <div class="container_hstart">
-                <input id="textinput" value="default text"></input>
+                <textarea id="textinput" value="default text"></textarea>
                 <div id="textsubmit" class="buttons"></div>
             </div>
             <!-- <button id="textsubmit"></button> -->
         </div>
 
-        <div id="transport">
-            <h2>Transport</h2>
-            <div id="container_tp" class="container_horiz"></div>
-        </div>
-        
-        <div id="marker_cue">
-            <div id="cue_label">
-                <h2>Play From Marker</h2>
+        <div id="button_interface">
+
+            <div id="transport">
+                <h2>Transport</h2>
+                <div id="container_tp" class="container_horiz"></div>
+            </div>
+            
+            <div id="marker_cue">
+                <div id="cue_label">
+                    <h2>Play From Marker</h2>
+                </div>
+                <div id="container_cue" class="container_horiz"></div>
             </div>
-            <div id="container_cue" class="container_horiz"></div>
-        </div>
 
-        <div id="misc" class="container_vert">
-            <h2>Misc. functions</h2>
-            <div id="container_misc" class="container_horiz"></div>
-        </div>
+            <div id="misc" class="container_vert">
+                <h2>Misc. functions</h2>
+                <div id="container_misc" class="container_horiz"></div>
+                <input type="file" id="file_input_json" accept=".json" style="display: none;">
+                <input type="file" id="file_input_audio" accept=".wav" style="display: none;">
+            </div>
 
-        <div id="regionprops" class="container_vert">
-            <h2>Region Properties</h2>
-            <div class="container_hstart">
-                <h3>Looping</h3>
-                <input type="checkbox" id="loop"/>
+            <div id="regionprops" class="container_vert">
+                <h2>Region Properties</h2>
+                <div class="container_hstart">
+                    <h3>Looping</h3>
+                    <input type="checkbox" id="loop"/>
+                </div>
             </div>
+
         </div>
 
 
index 32ed337c332c016f52062c90d010c4f49296f1fa..5782e48b4111c3b8a8f5e1f628dea245b9aabb1c 100644 (file)
@@ -3,7 +3,7 @@ html, body {
 
 body {
     background-color: #f0f0f0;
-    overflow: hidden;
+    /* overflow: hidden; */
     position: absolute;
     /* margin-left: -5px; */
 }
@@ -16,23 +16,13 @@ body {
     /* max-width: 940px; */
 }
 
-/*
-#background {
-    position: absolute; 
-    z-index: -1;
-    background-color: #000000;
-}
-*/
-
-
-/*
 #waveform {
-    padding: 25px;
+    /* padding: 25px; */
+    height: 128px; 
 }
-*/
 
 #waveform ::part(wrapper) {
-    height: 250px;
+    /* height: 350px; */
 }
 
 #waveform ::part(region-content) {
@@ -44,13 +34,12 @@ body {
     font-weight: 400;
     font-style: normal;
     height: 100%;
-    /*
-        background-color: rgba(0, 0, 100, 0.25) !important;
-        border: 1px solid #fff;
-        padding: 1px;
-        text-indent: 10px;
-        text-decoration: underline;
-        */
+}
+
+#droparea { 
+    border: 5px solid blue;
+    width: 100%;
+    height: 100px;
 }
 
 h1, h2, h3, p {
@@ -59,15 +48,20 @@ h1, h2, h3, p {
     font-style: normal;
 }
 
+/* top right bottom left */
 h1 {
     font-size: 24px;
+    margin: 0px 0px 15px 0px;
+    padding: 0px;
+}
+h2, h3 {
+    margin: 5px 0px 5px 0px;
+    padding: 0px;
 }
-
 h2  {
     width: 100%;
     font-size: 15px;
 }
-
 h3 {
     font-size: 12px;
 }
@@ -81,7 +75,7 @@ h3 {
     display: flex;
     flex-direction: column;
     flex-basis: auto;
-    justify-content: space-between;
+    /*justify-content: space-between;*/
 }
 .container_horiz {
     display: flex;
@@ -115,20 +109,24 @@ h3 {
 #textinput {
     /* width: 500px; */
     width: 100%;
+    height: 4em;
 }
 
 /* default button state */
+#button_interface {
+    display: flex;
+    flex-direction: column;
+    height: 80px;        
+}
+
 .buttons {
     display: flex;
     flex-wrap: wrap;
-    /* border: 2px solid black; */
     justify-content: center;
     background: #b6bfd3;
-    /* color: #000000; */
     color: #FFFFFF;
-    padding: 5px 20px 5px 20px;
+    padding: 5px 25px 5px 25px;
     margin: 5px;
-
 }
 
 .buttons.clicked {