diff --git a/app.js b/app.js index 5d831b8..45485ea 100644 --- a/app.js +++ b/app.js @@ -56,7 +56,7 @@ var PERIOD = Math.PI * 2; }; }); - app.directive('dx7ToggleButton', function() { + app.directive('toggleButton', function() { return { restrict: 'E', replace: true, @@ -70,13 +70,11 @@ var PERIOD = Math.PI * 2; app.directive('knob', function() { function link(scope, element, attrs) { var rotationRange = 300; // ±degrees - var pixelRange = 300; // pixels between max and min + var pixelRange = 200; // pixels between max and min var startY, startModel, down = false; var fgEl = element.find('div'); var max = element.attr('max'); var min = element.attr('min'); - console.log(fgEl); - element.on('mousedown', function(e) { startY = e.clientY; startModel = scope.ngModel || 0; @@ -117,6 +115,55 @@ var PERIOD = Math.PI * 2; }; }); + app.directive('slider', function() { + function link(scope, element, attrs) { + var sliderHandleHeight = 8; + var sliderRailHeight = 50; + var positionRange = sliderRailHeight - sliderHandleHeight; + var pixelRange = 50; + var startY, startModel, down = false; + var fgEl = element.find('div'); + var max = element.attr('max'); + var min = element.attr('min'); + element.on('mousedown', function(e) { + startY = e.clientY; + startModel = scope.ngModel || 0; + down = true; + e.preventDefault(); + e.stopPropagation(); + window.addEventListener('mousemove', onMove); + window.addEventListener('mouseup', onUp); + }); + + function onMove(e) { + if (down) { + var dy = (startY - e.clientY) * (max - min) / pixelRange; + scope.ngModel = Math.round(Math.max(min, Math.min(max, dy + startModel))); + scope.$apply(); + } + } + + function onUp(e) { + down = false; + window.removeEventListener('mousemove', onMove); + window.removeEventListener('mouseup', onUp); + } + + scope.getTop = function() { + return positionRange - ((this.ngModel - min) / (max - min) * positionRange); + } + } + + return { + restrict: 'E', + replace: true, + require: 'ngModel', + scope: {'ngModel': '='}, + template: '
', + link: link + }; + }); + app.controller('MidiCtrl', function($scope) { var mml = null; var mmlDemos = [ "t92 l8 o4 $" + @@ -202,8 +249,12 @@ var PERIOD = Math.PI * 2; } }; + this.onModeClick = function() { + console.log("hey ho"); + }; + this.onAnalysisChange = function() { - if (this.showAnalysis) { + if (this.analysisMode) { frequencybox.enable(); wavebox.enable(); } else { @@ -243,12 +294,19 @@ var PERIOD = Math.PI * 2; }); app.controller('OperatorCtrl', function($scope) { - $scope.$watchGroup(['operator.freqCoarse', 'operator.freqFine', 'operator.detune'], function() { + $scope.$watchGroup(['operator.oscMode', 'operator.freqCoarse', 'operator.freqFine', 'operator.detune'], function() { FMVoice.updateFrequency($scope.i); }); + $scope.$watch('operator.volume', function() { + FMVoice.setOutputLevel($scope.i, $scope.operator.volume); + console.log("outputLevel changed", $scope.operator.outputLevel); + }); + $scope.$watch('operator.pan', function() { + FMVoice.setPan($scope.i, $scope.operator.pan); + }); }); - app.controller('PresetCtrl', ['$localStorage', '$http', function ($localStorage, $http) { + app.controller('PresetCtrl', ['$scope', '$localStorage', '$http', function ($scope, $localStorage, $http) { this.lfoWaveformOptions = [ 'Triangle', 'Saw Down', 'Saw Up', 'Square', 'Sine', 'Sample & Hold' ]; var self = this; $http.get('roms/ROM1A.SYX') @@ -274,15 +332,16 @@ var PERIOD = Math.PI * 2; this.onChange = function() { console.log("changed preset!", this.selectedIndex); PARAMS = this.presets[this.selectedIndex]; + this.params = PARAMS; // TODO: separate UI parameters from internal synth parameters // TODO: better initialization of computed parameters for (var i = 0; i < PARAMS.operators.length; i++) { var op = PARAMS.operators[i]; - this.onVolumeChange(i, op); + FMVoice.setOutputLevel(i, op.volume); FMVoice.updateFrequency(i); - this.onPanChange(i, op.pan); + FMVoice.setPan(i, op.pan); } - this.onFeedbackChange(); + FMVoice.setFeedback(PARAMS.feedback); }; this.save = function() { @@ -299,22 +358,15 @@ var PERIOD = Math.PI * 2; } }; - this.onVolumeChange = function(operatorIndex, operator) { - FMVoice.setOutputLevel(operatorIndex, operator.volume); - console.log("outputLevel changed", operator.outputLevel); - }; - - this.onFeedbackChange = function() { + $scope.$watch('feedback', function() { FMVoice.setFeedback(PARAMS.feedback); console.log("fbRatio changed", PARAMS.fbRatio); - }; - - this.onLFOChange = function() {}; + }); - this.onPanChange = function(operatorIndex, value) { - FMVoice.setPan(operatorIndex, value); - console.log("pan changed", this.getOp(operatorIndex).outputLevelL, this.getOp(operatorIndex).outputLevelR); - }; + $scope.$watchGroup(['lfoSpeed', 'lfoDelay', 'lfoAmpModDepth', 'lfoPitchModDepth', 'lfoWaveform'], function() { + // TODO: update LFO stuff + // FMVoice.updateLFO(); + }); this.getOp = function(operatorIndex) { return this.presets[this.selectedIndex].operators[operatorIndex]; diff --git a/fonts/5x8_lcd_hd44780u_a02.eot b/fonts/5x8_lcd_hd44780u_a02.eot new file mode 100755 index 0000000..03621c6 Binary files /dev/null and b/fonts/5x8_lcd_hd44780u_a02.eot differ diff --git a/fonts/5x8_lcd_hd44780u_a02.svg b/fonts/5x8_lcd_hd44780u_a02.svg new file mode 100755 index 0000000..711f627 --- /dev/null +++ b/fonts/5x8_lcd_hd44780u_a02.svg @@ -0,0 +1,602 @@ + + + + +Created by FontForge 20110222 at Mon Mar 7 13:15:36 2011 + By www-data +Copyright vader381 2010 +"5x8 LCD HD44780U A02" is based on "LCD Dot Matrix Condensed" by "Havar Henriksen" (http://fontstruct.fontshop.com/fontstructors/farside), which is based on "LCD Dot Matrix" by "Havar Henriksen" (http://fontstruct.fontshop.com/fontstructors/farside) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/5x8_lcd_hd44780u_a02.ttf b/fonts/5x8_lcd_hd44780u_a02.ttf new file mode 100755 index 0000000..23319aa Binary files /dev/null and b/fonts/5x8_lcd_hd44780u_a02.ttf differ diff --git a/fonts/5x8_lcd_hd44780u_a02.woff b/fonts/5x8_lcd_hd44780u_a02.woff new file mode 100755 index 0000000..257f675 Binary files /dev/null and b/fonts/5x8_lcd_hd44780u_a02.woff differ diff --git a/fonts/digital-7__mono_italic_.eot b/fonts/digital-7__mono_italic_.eot new file mode 100755 index 0000000..a158e1f Binary files /dev/null and b/fonts/digital-7__mono_italic_.eot differ diff --git a/fonts/digital-7__mono_italic_.svg b/fonts/digital-7__mono_italic_.svg new file mode 100755 index 0000000..a9f0a24 --- /dev/null +++ b/fonts/digital-7__mono_italic_.svg @@ -0,0 +1,270 @@ + + + + +Created by FontForge 20110222 at Mon Jun 10 14:04:28 2013 + By www-data +Created by Sizenko Alexander. (c) 2008 Style-7. All rights reserved. http://www.styleseven.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/digital-7__mono_italic_.ttf b/fonts/digital-7__mono_italic_.ttf new file mode 100755 index 0000000..ddbd3f7 Binary files /dev/null and b/fonts/digital-7__mono_italic_.ttf differ diff --git a/fonts/digital-7__mono_italic_.woff b/fonts/digital-7__mono_italic_.woff new file mode 100755 index 0000000..2dcb1f2 Binary files /dev/null and b/fonts/digital-7__mono_italic_.woff differ diff --git a/images/13460FD783A2087D.png b/images/13460FD783A2087D.png new file mode 100644 index 0000000..f998279 Binary files /dev/null and b/images/13460FD783A2087D.png differ diff --git a/images/dx7-logo.png b/images/dx7-logo.png new file mode 100644 index 0000000..8ad1625 Binary files /dev/null and b/images/dx7-logo.png differ diff --git a/images/dx7-slider-foreground.svg b/images/dx7-slider-foreground.svg new file mode 100644 index 0000000..2e01109 --- /dev/null +++ b/images/dx7-slider-foreground.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/dx7-slider-rail-dashed.svg b/images/dx7-slider-rail-dashed.svg new file mode 100644 index 0000000..a3c5471 --- /dev/null +++ b/images/dx7-slider-rail-dashed.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/dx7-slider-rail.svg b/images/dx7-slider-rail.svg new file mode 100644 index 0000000..9522380 --- /dev/null +++ b/images/dx7-slider-rail.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/images/dx7-toggle-off-active.svg b/images/dx7-toggle-off-active.svg new file mode 100644 index 0000000..a3d8f50 --- /dev/null +++ b/images/dx7-toggle-off-active.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/dx7-toggle-off.svg b/images/dx7-toggle-off.svg new file mode 100644 index 0000000..6801cfb --- /dev/null +++ b/images/dx7-toggle-off.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/dx7-toggle-on-active.svg b/images/dx7-toggle-on-active.svg new file mode 100644 index 0000000..fa8b0d0 --- /dev/null +++ b/images/dx7-toggle-on-active.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/dx7-toggle-on.svg b/images/dx7-toggle-on.svg new file mode 100644 index 0000000..afb7a4c --- /dev/null +++ b/images/dx7-toggle-on.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/frequency-display.svg b/images/frequency-display.svg new file mode 100644 index 0000000..2f3dccd --- /dev/null +++ b/images/frequency-display.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/knob-background.svg b/images/knob-background.svg new file mode 100644 index 0000000..ad8bf3e --- /dev/null +++ b/images/knob-background.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/knob-foreground.svg b/images/knob-foreground.svg new file mode 100644 index 0000000..a9a8366 --- /dev/null +++ b/images/knob-foreground.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/lcd-background.svg b/images/lcd-background.svg new file mode 100644 index 0000000..6943f43 --- /dev/null +++ b/images/lcd-background.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/index.html b/index.html index c47b7bc..9e0e99b 100644 --- a/index.html +++ b/index.html @@ -7,134 +7,179 @@

MIDI Device: - - + - -

-
- Magnitude Spectrum - - Waveform - -
-
-
- Preset: - - -
-
Algorithm
-
{{ presetCtrl.presets[presetCtrl.selectedIndex].algorithm | number }}
- -
-
-
Feedback
-
{{ presetCtrl.presets[presetCtrl.selectedIndex].feedback | number : 0 }}
- -
-
LFO
-
-
Waveform
-
{{ presetCtrl.presets[presetCtrl.selectedIndex].lfoWaveform | number : 0 }}
- -
-
-
Speed
-
{{ presetCtrl.presets[presetCtrl.selectedIndex].lfoSpeed | number : 0 }}
- -
-
-
Delay
-
{{ presetCtrl.presets[presetCtrl.selectedIndex].lfoDelay | number : 0 }}
- -
-
-
Amp. Modulation
-
{{ presetCtrl.presets[presetCtrl.selectedIndex].lfoAmpModDepth | number : 0 }}
- -
-
-
Pitch Modulation
-
{{ presetCtrl.presets[presetCtrl.selectedIndex].lfoPitchModDepth | number : 0 }}
- -
-
-
Sync
- +
+
+ +
+
+ + +
+
-
-
OP {{ $index + 1 }}
- -
-
-
L{{ i + 1 }}
-
{{ operator.levels[i] | number : 0 }}
- +
+
Operator
+
Frequency
+
EG Rate
+
EG Level
+
Keyboard Scaling Not implemented
+
+
+
+
+
+
On/Off
+ +
+
+
Level
+
{{ operator.volume | number : 0 }}
+ +
+
+
Pan
+
{{ operator.pan | number : 0 }}
+ +
+
+
Vel Sens
+
{{ operator.velocitySens | number : 0 }}
+ +
+
+
LFO Sens
+
{{ operator.lfoAmpModSens | number : 0 }}
+ +
-
-
R{{ i + 1 }}
-
{{ operator.rates[i] | number : 0 }}
- +
+
+
Fixed
+ +
+
+
Coarse
+
{{ operator.freqCoarse | number : 0 }}
+ + +
+
+ {{ operator.freqRatio | number: 2 }} +
+
+ + {{ (operator.freqFixed | number).substr(0,5).replace(',','').replace('/\.$/','') }} +
+
+
Fine
+
{{ operator.freqFine | number : 0 }}
+ +
+
+
Detune
+
{{ operator.detune | number : 0 }}
+ +
+
+
+ +
+
+
+
+ +
+
+
+
+
Rate
+ +
+
+
Depth
+ +
+
+
Curve
+ +
+
+
Breakpt
+ +
+
+
Curve
+ +
+
+
Depth
+ +
+
+
-
-
Freq. Coarse
-
{{ operator.freqCoarse | number : 0 }}
- -
-
-
Freq. Fine
-
{{ operator.freqFine | number : 0 }}
- -
-
-
Detune
-
{{ operator.detune | number : 0 }}
- -
-
-
Volume
-
{{ operator.volume | number : 0 }}
- -
-
-
Velocity Sens.
-
{{ operator.velocitySens | number : 0 }}
- -
-
-
LFO Sens.
-
{{ operator.lfoAmpModSens | number : 0 }}
- -
-
-
Pan
-
{{ operator.pan | number : 0 }}
- -
-
-
Osc. Mode
- -
+
- diff --git a/synth.css b/synth.css index f031ddd..863ea0c 100644 --- a/synth.css +++ b/synth.css @@ -5,28 +5,64 @@ font-style:normal; } +@font-face { + font-family: "Digital-7 MonoItalic"; + src: url("fonts/digital-7__mono_italic_.eot?") format("eot"), url("fonts/digital-7__mono_italic_.woff") format("woff"), url("fonts/digital-7__mono_italic_.ttf") format("truetype"), url("fonts/digital-7__mono_italic_.svg#Digital-7MonoItalic") format("svg"); + font-weight: normal; + font-style: normal; +} + body { font-family: Helvetica, Arial, sans-serif; margin: 20px; - background-color: #313036; + background-color: #4a4950; color: #ffffff; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.display { + position: absolute; + width: 406px; + height: 56px; + top: 39px; + left: 254px; + background-color: #cfe14a; + box-shadow: inset 0 3px 0 3px #c0cf35; + background-image: url(images/lcd-background.svg); + background-repeat: no-repeat; + background-position: 0 0; +} + +.analysis { + position: absolute; + background-color: #c0cf35; + bottom: 8px; + right: 9px; + top: 13px; + width: 168px; } -.canvas-title { position: absolute; font-weight: 500; font-size: 12px; padding: 3px; } -canvas { display: block; } select.lcd { font-family: '5x8 LCD HD44780U A02 Regular', serif; font-size: 16.27px; - border: 1px solid #cfe14a; - padding: 1px 4px 3px; + line-height: 16px; + border: 0; + padding: 0; border-radius: 0; - background-color: #cfe14a; + background-color: transparent; appearance: none; -webkit-appearance: none; - box-shadow: inset 0 2px 0 1px rgba(0,0,0,0.1); //, inset 0 0 6px rgba(192,255,128,1); outline: 0; width: 160px; color: rgba(0,0,0,0.8); + position: absolute; + bottom: 8px; + left: 5px; } input[type='range'] { @@ -53,27 +89,18 @@ input[type='range']::-webkit-slider-thumb { } .algo-diagram { - width: 800px; + width: 800px; } .param-group { - float: left; - background: #232529; - xmargin-right: 10px; - padding: 10px; -} - -.param-label { - display: inline-block; - width: 80px; - font-size: 75%; - margin-right: 10px; - text-transform: uppercase; - vertical-align: middle; + margin-right: 10px; + display: inline-block; + vertical-align: top; + font-size: 0; } .param-value { - display: inline-block; + display: none; width: 40px; font-size: 75%; vertical-align: middle; @@ -139,9 +166,10 @@ input[type='range']::-webkit-slider-thumb { } .dx7-toggle { + display: block; width: 34px; height: 28px; - vertical-align: middle; + margin: 0 auto; background-color: #4a4950; background-image: url('images/dx7-toggle-off.svg'); border: 2px solid #232529; @@ -164,12 +192,117 @@ input[type='range']::-webkit-slider-thumb { background-image: url('images/dx7-toggle-on-active.svg'); } +.dx7-container { + background-color: #313036; + border: 1px solid #232326; + position: relative; + width: 1060px; +} + +.dx7-top-panel { + display: block; + height: 120px; + background-color: #232326; +} + +.dx7-headings { + font-size: 10px; + font-weight: bold; + position: relative; + display: block; + height: 12px; + margin: 16px 0 8px; + text-transform: uppercase; +} + +/* TODO: position absolute headings inside first row groups */ +.heading-operator { position: absolute; left: 30px; } +.heading-frequency { position: absolute; left: 260px; } +.heading-egrate { position: absolute; left: 500px; } +.heading-eglevel { position: absolute; left: 626px; } +.heading-keyboardscaling { position: absolute; left: 761px; } + +.dx7-logo { + position: absolute; + top: 40px; + left: 30px; + width: 153px; + height: 47px; + background-image: url(images/dx7-logo.png); + background-size: cover; +} + +.dx7-operators { + display: block; + top: 160px; +} + +.dx7-buttons-row-1 { + +} + +.dx7-buttons-row-2 { + +} + +.operator { + display: block; /* fix for spaces between inline children */ + padding: 15px 24px; + height: 50px; + font-size: 0; +} + +.operator:nth-child(odd) { + background-color: #36353b; +} + +.param { + position: relative; + display: inline-block; + width: 44px; + height: 50px; + vertical-align: top; +} + +.param.narrow { + width: 29px; +} + +.frequency-display { + display: inline-block; + width: 60px; + height: 43px; + box-sizing: border-box; + text-align: center; + padding: 4px; + background-image: url(images/frequency-display.svg); + background-position: 0 0; + background-repeat: no-repeat; + font-family: 'Digital-7 MonoItalic'; + letter-spacing: 1px; + font-size: 20px; + color: #fa0606; +} + +.param-label { + position: absolute; + top: 39px; + text-align: center; + display: inline-block; + width: 100%; + font-size: 8px; + font-weight: bold; + line-height: 9px; + text-transform: uppercase; + padding: 0 3px; + box-sizing: border-box; +} + .knob { + margin: 0 auto; height: 30px; width: 30px; background-image: url('images/knob-background.svg'); - display: inline-block; - vertical-align: middle; } .knob-foreground { @@ -177,4 +310,26 @@ input[type='range']::-webkit-slider-thumb { width: 30px; position: absolute; background-image: url('images/knob-foreground.svg'); +} + +.slider { + height: 50px; + width: 24px; + background-image: url('images/dx7-slider-rail-dashed.svg'); + background-size: 24px; + background-position: 0 0; + overflow: hidden; +} + +.param:last-child .slider { + width: 18px; +} + +.slider-foreground { + height: 13px; + width: 18px; + background-image: url('images/dx7-slider-foreground.svg'); + background-position: 0 0; + position: relative; + top: 0px; } \ No newline at end of file