Edit in JSFiddle

// import  vue@2.5.3
const EnvelopeGenerator = Vue.component('envelope-generator', {
  name: 'EnvelopeGenerator',
  template: "#adsr",
  props: {
    width: {
      type: Number,
      default: 640
    },
    height: {
      type: Number,
      default: 480
    },
    attack: {
      type: Number,
      required: true,
      validaor: v => 0 <= v && v <= 1
    },
    decay: {
      type: Number,
      required: true,
      validaor: v => 0 <= v && v <= 1
    },
    sustain: {
      type: Number,
      required: true,
      validaor: v => 0 <= v && v <= 1
    },
    release: {
      type: Number,
      required: true,
      validaor: v => 0 <= v && v <= 1
    }
  },
  data () {
    return {
      path: ''
    }
  },
  mounted() {
    this.draw();
  },
  watch: {
    attack: function () { this.draw(); },
    decay: function () { this.draw(); },
    sustain: function () { this.draw(); },
    release: function () { this.draw(); }
  },
  methods: {
    draw() {
      const wRetio = this.width / 4;
      const hRetio = this.height / 1;

			const paths = [];
      let x, y;
      x = y = 0;

      // attack
      x = this.attack * wRetio;
      y = 0;
      paths.push(`${x} ${y}`);

      // decay
      x += this.decay * wRetio;
      y = this.height - this.sustain * hRetio;
      paths.push(`${x} ${y}`);

      // sustain
      x += 1 * wRetio;
      paths.push(`${x} ${y}`);
      
      // release
      x += this.release * wRetio;
      y = this.height;
      paths.push(`${x} ${y}`);
      
      this.path = `M0 ${this.height},` + paths.join(',');
    }
  }
});

new Vue({
  el: '#app',
  components: { EnvelopeGenerator },
  data() {
    return {
      form: {
        attackTime: 0.5,
        decayTime: 0.3,
        sustainLevel: 0.5,
        releaseTime: 1.0
      },
      ctx: new AudioContext(),
      osc: null,
      adsr: null
    }
  },
  
  methods: {
    start() {
      this.osc = this.ctx.createOscillator();
      this.adsr = this.ctx.createGain();

      // osc -> gain -> output
      this.osc.connect(this.adsr);
      this.adsr.connect(this.ctx.destination);
      
      const t0 = this.ctx.currentTime;
      this.osc.start(t0);
      // vol:0
      this.adsr.gain.setValueAtTime(0, t0);
      // attack
      const t1 = t0 + this.form.attackTime;
      this.adsr.gain.linearRampToValueAtTime(1, t1);
      // decay
      const t2 = this.form.decayTime;
      this.adsr.gain.setTargetAtTime(this.form.sustainLevel, t1, t2);
    },
    stop() {
      const t = this.ctx.currentTime;
      this.adsr.gain.cancelScheduledValues(t);
      this.adsr.gain.setValueAtTime(this.adsr.gain.value, t);
      this.adsr.gain.setTargetAtTime(0, t, this.form.releaseTime);
    
      const stop = setInterval(() => {
        // 完全に0になるまでには時間がかかるため
        if (this.adsr.gain.value < 0.01) {
          this.osc.stop();
          clearInterval(stop);
        }
      }, 10);
    },
  }
});
<div id="app">
  <envelope-generator
    :width="600"
    :height="200"
    :attack="form.attackTime"
    :decay="form.decayTime"
    :sustain="form.sustainLevel"
    :release="form.releaseTime">
  </envelope-generator>
  <form class="envelope-controller">
    <div>
      <label>Attack</label>
      <input type="range" min="0" max="1" step="0.01" v-model.number="form.attackTime">
    </div>
    <div>
      <label>Decay</label>
      <input type="range" min="0" max="1" step="0.01" v-model.number="form.decayTime">
    </div>
    <div>
      <label>Sustain</label>
      <input type="range" min="0" max="1" step="0.01" v-model.number="form.sustainLevel">
    </div>
    <div>
      <label>Release</label>
      <input type="range" min="0" max="1" step="0.01" v-model.number="form.releaseTime">
    </div>
    <button type="button" @click="start">Start</button>
    <button type="button" @click="stop">Stop</button>
  </form>
</div>

<script type="text/x-template" id="adsr">
  <svg :width="width" :height="height" xmlns="http://www.w3.org/2000/svg" baseProfile="full">
    <path :d="path" stroke="#666666" stroke-width="3" fill="none"></path>
  </svg>
</script>
label {
  display: inline-block;
  width: 70px;
}

svg {
  background-color: white;
  border: 1px solid rgba(6,6,6,.3);
  padding: 10px;
}