Build a Vue.js Piano Music MP3 Keyboard Player and Recorder in Browser Using Vanilla Javascript Full Project For Beginners

  • Post author:
  • Post category:Vue
  • Post comments:0 Comments

 

 

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" />
<div id="app">
    <div class="audioplayer" v-for="s in sounddata"><audio v-bind:data-num="s.number" preload="auto">
            <source v-bind:src="s.url" type="audio/ogg" />
        </audio></div>
    <div class="center_box">
        <h2>Vue.js Piano Project 7</h2>
        <div class="keyboard">
            <div class="pianokey" v-for="s in display_keys">
                <div class="white" v-if="s.type=="white"" v-on:click="addnote(s.num)" v-bind:class="get_current_highlight(s.num,s.key)?"playing":""">
                    <div class="label">{{String.fromCharCode(s.key)}}</div>
                </div>
                <div class="black" v-if="s.type=="black"" v-on:click="addnote(s.num)" v-bind:class="get_current_highlight(s.num,s.key)?"playing":""">
                    <div class="label">{{String.fromCharCode(s.key)}}</div>
                </div>
            </div>
        </div><br />
        <div class="controls">
            <ul class="notes_list" v-if="notes.length>0">
                <li v-for="(note,id) in notes" v-bind:class="now_note_id-1==id?"playing":""">
                    <div class="num">{{note.num}}</div>
                    <div class="time">{{note.time}}</div>
                </li>
            </ul><button v-on:click="load_sample">Sample</button><button v-on:click="playnext(1)">Playnext</button><button v-if="playing_time<=1" v-on:click="startplay">Startplay<i class="fa fa-play"></i></button><button v-if="playing_time>1" v-on:click="stopplay">Stopplay<i class="fa fa-pause"></i></button><button v-if="record_time<=0" v-on:click="start_record">Record<i class="fa fa-circle"></i></button><button v-if="record_time>=1" v-on:click="stop_record">StopRecord<i class="fa fa-top"></i></button><button v-on:click="notes=[]">Clear</button>
            <h4>{{playing_time+record_time}}</h4>
        </div>
    </div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.js"></script>

 

 

*
  vertical-align: top
  font-family: 微軟正黑體
  backface-visibility: hidden
  

$key_width: 44px
$key_height: 300px

$color_white: #eee
$color_black: #585858

@mixin size($w,$h)
  width: $w
  height: $h

html,body
  +size(100%,100%)
  margin: 0
  padding: 0
  
h2
  margin-bottom: 30px
  color: $color_black
  
button
  background-color: transparent
  border: none
  border: solid 1px
  padding: 4px 12px
  border-radius: 4px
  transition: 0.5s
  cursor: pointer
  vertical-align: middle
  &:hover
    background-color: $color_black
    color: white
  
.notes_list
  li
    display: inline-block
    border-right: solid 1px
    padding: 2px 5px
    cursor: pointer
    transition: 0.3s
    
    &:hover
      background-color: darken($color_white,5)
    &.playing
      background-color: darken($color_white,10)
    .time
      font-size: 8px
      opacity: 0.3
    .num
      font-size: 16px
  
.center_box
  position: absolute
  left: 50%
  top: 50%
  transform: translate(-50%,-50%)
  text-align: center
  width: 100%
  
.keyboard
  box-shadow: 0px 0px 40px -5px rgba(0,0,0,0.4)
  display: inline-block
  margin-bottom: 30px
  
.pianokey
  display: inline-block
  position: relative
  cursor: pointer
  
.white.playing
  background-color: darken($color_white,10)
  transform: translate(0px,0px)
  
.black.playing
  background-color: lighten($color_black,10)
  transform: translate(0px,0px)
  
  
.white
  +size($key_width,$key_height)
  border: solid 1px $color_white
  transform: translate(-3px,-3px)
  transition: 0.1s
  &:hover
    transform: translate(0px,0px)
    background-color: $color_white
  
.black
  position: absolute
  top: 0px
  width: $key_width/2
  height: $key_height*0.55
  background-color: $color_black
  margin-left: -$key_width/4
  margin-right: -$key_width/4
  z-index: 20
  transform: translate(-3px,-3px)
  transition: 0.1s
  &:hover
    transform: translate(0px,0px)
    background-color: darken($color_black,10)
  
.label
  position: absolute
  color: rgba($color_black,0.5)
  bottom: -25px
  left: 50%
  transform: translate(-50%)
  font-size: 8px
  
i
  margin-left: 5px
  margin-right: 0px
  margin-top: 3px
i.fa-circle
  color: darken(red,10)

 

See also  Vue.js Digital Clock With Current Time Using Moment.js and CSS Bulma Framework in Browser Using Javascript Full Project For Beginners

 

var soundpack=[];
var soundpack_index=[1,1.5,2,2.5,3,3.5,4,4.5,5,5.5,6,6.5,7,8,8.5,9,9.5,10,11,11.5,12,12.5,13,13.5,14,15];
for(var i=0;i<soundpack_index.length;i++){
  soundpack.push({
    number: soundpack_index[i],
    url: "https://awiclass.monoame.com/pianosound/set/"+ soundpack_index[i]+".wav"
  });
  
}

var vm = new Vue({
  el: "#app",
  data: {
    sounddata: soundpack,
    notes: [{"num":1,"time":150},{"num":1,"time":265},{"num":5,"time":380},{"num":5,"time":501},{"num":6,"time":625},{"num":6,"time":748},{"num":5,"time":871},{"num":4,"time":1126},{"num":4,"time":1247},{"num":3,"time":1365},{"num":3,"time":1477},{"num":2,"time":1597},{"num":2,"time":1714},{"num":1,"time":1837}],
    now_note_id: 0,
    next_note_id: 0,
    playing_time: 0,
    record_time: 0,
    now_press_key: -1,
    player: null,
    recorder: null,
    display_keys:[
      {num: 1,key: 90  ,type:'white'},
      {num: 1.5,key: 83  ,type:'black'},
      {num: 2,key: 88  ,type:'white'},
      {num: 2.5,key: 68  ,type:'black'},
      {num: 3,key: 67  ,type:'white'},
      {num: 4,key: 86  ,type:'white'},
      {num: 4.5,key: 71  ,type:'black'},
      {num: 5,key: 66  ,type:'white'},
      {num: 5.5,key: 72  ,type:'black'},
      {num: 6,key: 78  ,type:'white'},
      {num: 6.5,key: 74  ,type:'black'},
      {num: 7,key: 77  ,type:'white'},
      {num: 8,key: 81  ,type:'white'},
      {num: 8.5,key: 50  ,type:'black'},
      {num: 9,key: 87  ,type:'white'},
      {num: 9.5,key: 51,type:'black'},
      {num: 10,key: 69  ,type:'white'},
      {num: 11,key: 82  ,type:'white'},
      {num: 11.5,key: 53  ,type:'black'},
      {num: 12,key: 84  ,type:'white'},
      {num: 12.5,key: 54  ,type:'black'},
      {num: 13,key: 89  ,type:'white'},
      {num: 13.5,key: 55  ,type:'black'},
      {num: 14,key: 85  ,type:'white'},
      {num: 15,key: 73  ,type:'white'}
      
    ]
  },
  methods: {
    playnote: function(id,volume){
      if (id>0){
        var audio_obj=$("audio[data-num='"+id+"']")[0];
        audio_obj.volume=volume;
        audio_obj.currentTime=0;
        audio_obj.play();
      }
    },
    playnext: function(volume){
      var play_note=this.notes[this.now_note_id].num;
      console.log(play_note);
      this.playnote(play_note,volume);
      this.now_note_id+=1;
      
      if (this.now_note_id>=this.notes.length){
        this.stopplay();
      }
    },
    start_record: function(){
      this.record_time=0;
      this.recorder=setInterval(function(){
        vm.record_time++;
      })
    },
    stop_record: function(){
      clearInterval(this.recorder);
      this.record_time=0;
      
    },
    startplay: function(){
      this.now_note_id=0;
      this.playing_time=0;
      this.next_note_id=0;
      var vobj=this;
      this.player=setInterval(function(){
        if (vobj.playing_time>=vobj.notes[vobj.next_note_id].time){
          vobj.playnext(1);
          vobj.next_note_id++;
        }
        vobj.playing_time++;
      },2);
    },
    stopplay: function(){
      clearInterval(this.player);
      this.now_note_id=0;
      this.playing_time=0;
      this.next_note_id=0;
    },
    get_current_highlight: function(id,skey){
      if (this.now_press_key==skey)
        return true;
      if (this.notes.length==0)
        return false
      var cur_id=this.now_note_id-1;
      if (cur_id<0) cur_id=0;
      var num=this.notes[cur_id].num;
      if (num==id)
        return true;
      return false;
    },
    addnote: function(id){
      if (this.record_time>0)
        this.notes.push({num: id,time: this.record_time});
      this.playnote(id,1);
    },
    load_sample: function(){
      var vobj=this;
      $.ajax({
        url: "https://awiclass.monoame.com/api/command.php?type=get&name=music_dodoro",
        success: function(res){
          vobj.notes=JSON.parse(res);
        }
      });
    }
  }
});

$(window).keydown(function(e){
  var key = e.which;
  vm.now_press_key=key;
  console.log(key);
  for(var i=0;i<vm.display_keys.length;i++){
    if (key==vm.display_keys[i].key){
      vm.addnote(vm.display_keys[i].num)
    }
  }
});

$(window).keyup(function(){
  vm.now_press_key=-1;
});

Leave a Reply