LoginSignup
12
11

More than 5 years have passed since last update.

楽器の練習用アプリ

Last updated at Posted at 2016-04-03

音程を維持しつつ再生速度を変えつつ楽器を持つ間を設ける

<!DOCTYPE html>
<html>
<head>
<style>
.rate,
.count{
  width: 300px;
}
</style>
<title></title>
<meta charset="utf-8">
</head>
<body>
<h1>楽器のおとも</h1>

<div>
  <h3>音声ファイル</h3>
  <input type="file"/>
</div>
<div>
  <h3>再生速度</h3>
  <input class="rate" type="range" min=".5" max="1.5" step=".1" value="1">
  <span class="dispRate"></span>倍速
</div>
<div>
  <h3>再生開始までの秒数</h3>
  <input class="count" type="range" min="1" max="10" step="1" value="5">
  <span class="dispCount"></span></div>
<div>
  <button class="start">再生</button>
  <button class="stop">停止</button>
</div>
<script>

var player = {
  src: '',
  audio: '',
  count: 1,
  currentCount: 1,
  rate: 1,
  cancelDelay: '',
  watchCb: [],
  setCount: function( count ){
    this.execWatchCb('count', this.count = count);
    this.setCurrentCount( count );
  },
  setRate: function( rate ){
    this.execWatchCb('rate', this.rate = rate);
    if( this.audio ){
      this.audio.playbackRate = this.rate;
    }
  },
  setSrc: function( src ){
    this.execWatchCb('src', this.src = src);
  },
  setCurrentCount: function( count ){
    this.execWatchCb('currentCount', this.currentCount = count);
  },
  play: function(){
    if( !this.src ) return false;
    this.stop();
    this.audio = new Audio( this.src );
    var count = player.count * 1000;
    this.cancelDelay = delay(
      function(){
        if( player.audio ){
          player.audio.playbackRate = player.rate;
          player.audio.play();
        }
      },
      count,
      function( elapsedTime ){
        player.setCurrentCount( Math.floor((count - elapsedTime)/1000) );
      }
    );
  },
  stop: function(){
    if( this.cancelDelay ){
      this.cancelDelay();
    }
    if( this.audio ){
      this.audio.pause();
    }
  },
  watch: function( cb ){
    this.watchCb.push( cb );
  },
  execWatchCb: function( name, value){
    var o = this;
    setTimeout(function(){
      o.watchCb.forEach(function( cb ){
        cb(name, value);
      });
    },0)
  }
};


var el = {
  fileSelector: document.querySelector('[type="file"]'),
  start: document.querySelector('.start'),
  stop: document.querySelector('.stop'),
  rate: document.querySelector('.rate'),
  dispRate: document.querySelector('.dispRate'),
  count: document.querySelector('.count'),
  dispCount: document.querySelector('.dispCount')
};

el.fileSelector.addEventListener('change', function(event) {
    var file = event.target.files[0];
    if (!(file instanceof File)) {
        window.alert('Please upload file.');
    } else if (file.type.indexOf('audio') === -1) {
        window.alert('Please upload audio file.');
    } else {
      player.setSrc( window.URL.createObjectURL(file) );
    }
}, false);


player.watch(function(name, value){
  if( name === 'currentCount'){
    el.count.value = value;
    el.dispCount.textContent = value;
  }
  else if( name === 'rate'){
    el.rate.value = value;
    el.dispRate.textContent = value;
  }
});

player.setCount(5);
player.setRate(.8);

el.start.addEventListener('click', function(){
  player.play();
});

el.stop.addEventListener('click', function(){
  player.stop();
});

el.rate.addEventListener('change', function(){
  player.setRate( this.value );
});

el.count.addEventListener('change', function(){
  player.setCount( this.value );
});

function delay(cb, delayTime, everyTimeCb){
  var cancel = false;
  delayTime = delayTime || 0;
  (function(){
    var baseTime;
    var raf = window.requestAnimationFrame;
    raf(function(now){
      baseTime = baseTime || now;
      var elapsedTime = now - baseTime;
      if(elapsedTime >= delayTime){
        cb(now);
      }
      else{
        everyTimeCb( elapsedTime );
        cancel || raf(arguments.callee);
      }
    });
  })();
  return function(){
    cancel = true;
  };
};

</script>
</body>
</html>

12
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
11