<commit_before>"use strict";

var app = angular.module('js100', []);

app.controller('controller', ['$scope', function($scope) {
  var audioContext;
  var transport;

  $scope.playing = false;
  $scope.waveform = 'sawtooth';
  $scope.amplitude = 0.75;
  $scope.lfoWaveform = 'sine'
  $scope.lfoFrequency = 5;
  $scope.lfoAmplitude = 0;
  $scope.filterCutoff = 1000;
  $scope.filterResonance = 0;
  $scope.filterLFOWaveform = 'sine'
  $scope.filterLFOFrequency = 5;
  $scope.filterLFOAmplitude = 0;
  $scope.envelopeAttack = 0.0;
  $scope.envelopeDecay = 0.0;
  $scope.envelopeSustain = 1.0;
  $scope.envelopeRelease = 0.0;
  $scope.tempo = 100;
  $scope.loop = true;
  $scope.notes = [{name: 'C3'},
                  {name: ''},
                  {name: 'Eb3'},
                  {name: 'F3'},
                  {name: 'G3'},
                  {name: 'Bb4'},
                  {name: 'F3'}, 
                  {name: 'Bb4'}];

  var toGenericConfig = function() {
    var filterCutoff = parseInt($scope.filterCutoff, 10);

    return {
      waveform:           $scope.waveform,
      amplitude:          parseFloat($scope.amplitude),
      lfoWaveform:        $scope.lfoWaveform,
      lfoFrequency:       parseFloat($scope.lfoFrequency),
      lfoAmplitude:       parseInt($scope.lfoAmplitude, 10),
      filterCutoff:       filterCutoff,
      filterResonance:    parseInt($scope.filterResonance, 10),
      filterLFOWaveform:  $scope.filterLFOWaveform,
      filterLFOFrequency: parseFloat($scope.filterLFOFrequency),
      filterLFOAmplitude: parseFloat($scope.filterLFOAmplitude) * filterCutoff,
      envelopeAttack:     parseFloat($scope.envelopeAttack),
      envelopeDecay:      parseFloat($scope.envelopeDecay),
      envelopeSustain:    parseFloat($scope.envelopeSustain),
      envelopeRelease:    parseFloat($scope.envelopeRelease),
    };
  };

  var parseNotes = function() {
    var rawNotes = [];

    for (var i = 0; i < $scope.notes.length; i++) {
      rawNotes[i] = $scope.notes[i].name;
    }

    return rawNotes.join(' ');
  };

  var stopCallback = function() {
    $scope.playing = false;
    $scope.$digest();
  };

  $scope.init = function() {
    if ('AudioContext' in window) {
      audioContext = new AudioContext();

      var config = toGenericConfig();
      var instrument = new JSSynth.Instrument(audioContext, config);

      transport = new JSSynth.Transport(audioContext, instrument, parseNotes(), parseInt($scope.tempo, 10), $scope.loop, stopCallback);
    }
    else {
      alert("Your browser doesn't appear to be cool enough to run the JS-100");
      return;
    }
  };
  $scope.init();

  $scope.updateInstrument = function() {
    var config = toGenericConfig();
    console.log(config);
    var instrument = new JSSynth.Instrument(audioContext, config);
    transport.instrument = instrument;
  };

  $scope.updateNotes = function() {
    transport.updateNotes(parseNotes());
  };

  $scope.updateTempo = function() {
    transport.updateTempo(parseInt($scope.tempo, 10));
  };

  $scope.updateLoop = function() {
    transport.loop = $scope.loop;
  };

  $scope.toggle = function() {
    transport.toggle();
    $scope.playing = !$scope.playing;
  };
}]);

// Adapted from:
// http://stackoverflow.com/questions/19094150/using-angularjs-directive-to-format-input-field-while-leaving-scope-variable-unc
// http://jsfiddle.net/KPeBD/2/
app.directive('noteInput', function () {
  return {
    require: 'ngModel',
    link: function (scope, element, attrs, ctrl) {
       if (!ctrl) return;

       function formatNoteValue(rawValue) {
         var formattedValue = rawValue;
         formattedValue = formattedValue.replace("##", "𝄪");
         formattedValue = formattedValue.replace("#", "♯");
         formattedValue = formattedValue.replace("bb", "𝄫");
         formattedValue = formattedValue.replace("b", "♭");

         return formattedValue;
       };

       ctrl.$formatters.push(function (a) {
         return formatNoteValue(ctrl.$modelValue);
       });

       element.bind('blur', function(e) {
         element.val(formatNoteValue(element.val()));
       });

       element.bind('keydown', function(e) {
         if (e.keyCode === 32) {
           element.val('');
         }
         else if (e.keyCode === 37) {  // Left arrow key
           if (element[0].selectionStart === 0 && !(element.hasClass('first'))) {
             var noteIndex = parseInt(element[0].id.split("-")[1], 10);
             var nextNoteId = 'note-' + (noteIndex - 1);
           
             document.getElementById(nextNoteId).focus();
           }
         }
         else if (e.keyCode === 39) {  // Right arrow key
           if (element[0].selectionEnd === element.val().length && !(element.hasClass('last'))) {<commit_msg>Allowing lowercase note names in input<commit_after>"use strict";

var app = angular.module('js100', []);

app.controller('controller', ['$scope', function($scope) {
  var audioContext;
  var transport;

  $scope.playing = false;
  $scope.waveform = 'sawtooth';
  $scope.amplitude = 0.75;
  $scope.lfoWaveform = 'sine'
  $scope.lfoFrequency = 5;
  $scope.lfoAmplitude = 0;
  $scope.filterCutoff = 1000;
  $scope.filterResonance = 0;
  $scope.filterLFOWaveform = 'sine'
  $scope.filterLFOFrequency = 5;
  $scope.filterLFOAmplitude = 0;
  $scope.envelopeAttack = 0.0;
  $scope.envelopeDecay = 0.0;
  $scope.envelopeSustain = 1.0;
  $scope.envelopeRelease = 0.0;
  $scope.tempo = 100;
  $scope.loop = true;
  $scope.notes = [{name: 'C3'},
                  {name: ''},
                  {name: 'Eb3'},
                  {name: 'F3'},
                  {name: 'G3'},
                  {name: 'Bb4'},
                  {name: 'F3'}, 
                  {name: 'Bb4'}];

  var toGenericConfig = function() {
    var filterCutoff = parseInt($scope.filterCutoff, 10);

    return {
      waveform:           $scope.waveform,
      amplitude:          parseFloat($scope.amplitude),
      lfoWaveform:        $scope.lfoWaveform,
      lfoFrequency:       parseFloat($scope.lfoFrequency),
      lfoAmplitude:       parseInt($scope.lfoAmplitude, 10),
      filterCutoff:       filterCutoff,
      filterResonance:    parseInt($scope.filterResonance, 10),
      filterLFOWaveform:  $scope.filterLFOWaveform,
      filterLFOFrequency: parseFloat($scope.filterLFOFrequency),
      filterLFOAmplitude: parseFloat($scope.filterLFOAmplitude) * filterCutoff,
      envelopeAttack:     parseFloat($scope.envelopeAttack),
      envelopeDecay:      parseFloat($scope.envelopeDecay),
      envelopeSustain:    parseFloat($scope.envelopeSustain),
      envelopeRelease:    parseFloat($scope.envelopeRelease),
    };
  };

  var parseNotes = function() {
    var rawNotes = [];

    for (var i = 0; i < $scope.notes.length; i++) {
      rawNotes[i] = $scope.notes[i].name;
    }

    return rawNotes.join(' ');
  };

  var stopCallback = function() {
    $scope.playing = false;
    $scope.$digest();
  };

  $scope.init = function() {
    if ('AudioContext' in window) {
      audioContext = new AudioContext();

      var config = toGenericConfig();
      var instrument = new JSSynth.Instrument(audioContext, config);

      transport = new JSSynth.Transport(audioContext, instrument, parseNotes(), parseInt($scope.tempo, 10), $scope.loop, stopCallback);
    }
    else {
      alert("Your browser doesn't appear to be cool enough to run the JS-100");
      return;
    }
  };
  $scope.init();

  $scope.updateInstrument = function() {
    var config = toGenericConfig();
    console.log(config);
    var instrument = new JSSynth.Instrument(audioContext, config);
    transport.instrument = instrument;
  };

  $scope.updateNotes = function() {
    transport.updateNotes(parseNotes());
  };

  $scope.updateTempo = function() {
    transport.updateTempo(parseInt($scope.tempo, 10));
  };

  $scope.updateLoop = function() {
    transport.loop = $scope.loop;
  };

  $scope.toggle = function() {
    transport.toggle();
    $scope.playing = !$scope.playing;
  };
}]);

// Adapted from:
// http://stackoverflow.com/questions/19094150/using-angularjs-directive-to-format-input-field-while-leaving-scope-variable-unc
// http://jsfiddle.net/KPeBD/2/
app.directive('noteInput', function () {
  return {
    require: 'ngModel',
    link: function (scope, element, attrs, ctrl) {
       if (!ctrl) return;

       function formatNoteValue(rawValue) {
         var formattedValue = rawValue;
         formattedValue = formattedValue.replace("##", "𝄪");
         formattedValue = formattedValue.replace("#", "♯");
         formattedValue = formattedValue.replace("bb", "𝄫");
         formattedValue = formattedValue.replace("b", "♭");

         return formattedValue;
       };

       ctrl.$formatters.push(function (a) {
         return formatNoteValue(ctrl.$modelValue);
       });

       ctrl.$parsers.push(function (viewValue) {
         var parsedValue = viewValue;
         parsedValue = parsedValue.toUpperCase();
         parsedValue = parsedValue.replace("♯", "#");
         parsedValue = parsedValue.replace("𝄪", "##");
         parsedValue = parsedValue.replace("♭", "b");
         parsedValue = parsedValue.replace("𝄫", "bb");
         
         return parsedValue;
       });

       element.bind('blur', function(e) {
         element.val(formatNoteValue(element.val()));
       });

       element.bind('keydown', function(e) {
         if (e.keyCode === 32) {
           element.val('');
         }
         else if (e.keyCode === 37) {  // Left arrow key
           if (element[0].selectionStart === 0 && !(element.hasClass('first'))) {
             var noteIndex = parseInt(element[0].id.split("-")[1], 10);
             var nextNoteId = 'note-' + (noteIndex - 1);
           
             document.getElementById(nextNoteId).focus();
           }
         }
         else if (e.keyCode === 39) {  // Right arrow key
           if (element[0].selectionEnd === element.val().length && !(element.hasClass('last'))) {
{'fraction_non_alphanumeric': 0.15194062782067996, 'fraction_numerical': 0.014040718082439074, 'mean_word_length': 2.636761487964989, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '163985', 'n_tokens_mistral': 3307, 'n_tokens_neox': 3102, 'n_words': 574}