<commit_before>import React, { Component } from 'react';
import TabStaff from './TabStaff';
import _ from 'lodash';
import song from './song';

export default class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      song: song,
      current: {
        measure: 0,
        noteIndex: 0
      },
      audioContext: new AudioContext(),
      isPlaying: false,
      bpm: 120
    };
  }

  getSpeedFromBpm = (bpm) => {
    return 60000 / bpm;
  }

  startPlayback = () => {
    let startTimestamp = Date.now();
    this.playCurrentNote();

    this.setState({
      timer: requestAnimationFrame(() => {
        this.loopThroughSong(startTimestamp);
      })
    });
  }

  getReplaySpeedForNote = (note, bpm) => {
    let noteLength = note.duration[0];

    let replaySpeed = this.getSpeedFromBpm(bpm);
    if(noteLength === 'h') {
      replaySpeed = replaySpeed * 2;
    } else if(noteLength === 'e') {
      replaySpeed = replaySpeed / 2;
    }

    return replaySpeed;
  }

  loopThroughSong = (startTimestamp) => {
    let { current, bpm } = this.state;
    let { measure, noteIndex } = current;

    let currentTimestamp = Date.now();
    let replayDiff = currentTimestamp - startTimestamp;
    let replaySpeed = this.getReplaySpeedForNote(song[current.measure].notes[noteIndex], bpm);

    if(replayDiff >= replaySpeed) {
      if(measure === song.length - 1 && noteIndex === song[measure].notes.length - 1) {
        this.handleStop();
      } else if(measure !== song.length - 1 && noteIndex === song[measure].notes.length - 1) {
        this.setState({
          current: {
            measure: measure + 1,
            noteIndex: 0
          },
          timer: requestAnimationFrame(() => {
            this.loopThroughSong(currentTimestamp);
          })
        }, this.playCurrentNote);
      } else {
        this.setState({
          current: {
            measure: measure,
            noteIndex: noteIndex + 1
          },
          timer: requestAnimationFrame(() => {
            this.loopThroughSong(currentTimestamp);
          })
        }, this.playCurrentNote);
      }
    } else {
      this.setState({
        timer: requestAnimationFrame(() => {
          this.loopThroughSong(startTimestamp);
        })
      });
    }
  }

  playCurrentNote = () => {
    let noteToPlay = song[this.state.current.measure].notes[this.state.current.noteIndex];
    let replaySpeed = this.getReplaySpeedForNote(noteToPlay, this.state.bpm);

    this.playNoteAtTime(noteToPlay, this.state.audioContext.currentTime, replaySpeed);
  }

  play = (startTime, pitch, duration) => {
    let endTime = startTime + duration;

    let oscillator = this.state.audioContext.createOscillator();
    let gainNode = this.state.audioContext.createGain();
    oscillator.connect(gainNode);
    gainNode.connect(this.state.audioContext.destination);

    oscillator.type = 'square';
    oscillator.detune.value = (pitch - 29) * 100;

    gainNode.gain.value = 0.025;

    oscillator.start(startTime);
    oscillator.stop(endTime);
  }

  playNoteAtTime = (currentNote, playTime, duration) => {
    for(let i = 0; i < currentNote.string.length; i++) {
      let pitch = currentNote.fret[i] + (5 * currentNote.string[i]);
      if(currentNote.string[i] >= 4) {
        pitch = pitch - 1;
      }

      this.play(playTime, pitch, duration / 1000);
    }
  }

  handleStop = () => {
    cancelAnimationFrame(this.state.timer);

    this.setState({
      isPlaying: false,
      current: {
        measure: 0,
        noteIndex: 0
      }
    });
  }

  handlePlay = (event) => {
    this.setState({
      isPlaying: true,
      startTime: this.state.audioContext.currentTime + .005,<commit_msg>16th notes and do not play if already playing<commit_after>import React, { Component } from 'react';
import TabStaff from './TabStaff';
import _ from 'lodash';
import song from './song';

export default class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      song: song,
      current: {
        measure: 0,
        noteIndex: 0
      },
      audioContext: new AudioContext(),
      isPlaying: false,
      bpm: 120
    };
  }

  getSpeedFromBpm = (bpm) => {
    return 60000 / bpm;
  }

  startPlayback = () => {
    let startTimestamp = Date.now();
    this.playCurrentNote();

    this.setState({
      timer: requestAnimationFrame(() => {
        this.loopThroughSong(startTimestamp);
      })
    });
  }

  getReplaySpeedForNote = (note, bpm) => {
    let noteLength = note.duration[0];

    let replaySpeed = this.getSpeedFromBpm(bpm);
    if(noteLength === 'h') {
      replaySpeed = replaySpeed * 2;
    } else if(noteLength === 'e') {
      replaySpeed = replaySpeed / 2;
    } else if(noteLength === 's') {
      replaySpeed = replaySpeed / 4;
    }

    return replaySpeed;
  }

  loopThroughSong = (startTimestamp) => {
    let { current, bpm } = this.state;
    let { measure, noteIndex } = current;

    let currentTimestamp = Date.now();
    let replayDiff = currentTimestamp - startTimestamp;
    let replaySpeed = this.getReplaySpeedForNote(song[current.measure].notes[noteIndex], bpm);

    if(replayDiff >= replaySpeed) {
      if(measure === song.length - 1 && noteIndex === song[measure].notes.length - 1) {
        this.handleStop();
      } else if(measure !== song.length - 1 && noteIndex === song[measure].notes.length - 1) {
        this.setState({
          current: {
            measure: measure + 1,
            noteIndex: 0
          },
          timer: requestAnimationFrame(() => {
            this.loopThroughSong(currentTimestamp);
          })
        }, this.playCurrentNote);
      } else {
        this.setState({
          current: {
            measure: measure,
            noteIndex: noteIndex + 1
          },
          timer: requestAnimationFrame(() => {
            this.loopThroughSong(currentTimestamp);
          })
        }, this.playCurrentNote);
      }
    } else {
      this.setState({
        timer: requestAnimationFrame(() => {
          this.loopThroughSong(startTimestamp);
        })
      });
    }
  }

  playCurrentNote = () => {
    let noteToPlay = song[this.state.current.measure].notes[this.state.current.noteIndex];
    let replaySpeed = this.getReplaySpeedForNote(noteToPlay, this.state.bpm);

    this.playNoteAtTime(noteToPlay, this.state.audioContext.currentTime, replaySpeed);
  }

  play = (startTime, pitch, duration) => {
    let endTime = startTime + duration;

    let oscillator = this.state.audioContext.createOscillator();
    let gainNode = this.state.audioContext.createGain();
    oscillator.connect(gainNode);
    gainNode.connect(this.state.audioContext.destination);

    oscillator.type = 'square';
    oscillator.detune.value = (pitch - 29) * 100;

    gainNode.gain.value = 0.025;

    oscillator.start(startTime);
    oscillator.stop(endTime);
  }

  playNoteAtTime = (currentNote, playTime, duration) => {
    for(let i = 0; i < currentNote.string.length; i++) {
      let pitch = currentNote.fret[i] + (5 * currentNote.string[i]);
      if(currentNote.string[i] >= 4) {
        pitch = pitch - 1;
      }

      this.play(playTime, pitch, duration / 1000);
    }
  }

  handleStop = () => {
    cancelAnimationFrame(this.state.timer);

    this.setState({
      isPlaying: false,
      current: {
        measure: 0,
        noteIndex: 0
      }
    });
  }

  handlePlay = (event) => {
    if(this.state.isPlaying) {
      return;
    }

    this.setState({
      isPlaying: true,
      startTime: this.state.audioContext.currentTime + .005,
{'fraction_non_alphanumeric': 0.13425378040762656, 'fraction_numerical': 0.011439842209072978, 'mean_word_length': 2.404655326768129, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 33, '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': '881756', 'n_tokens_mistral': 2448, 'n_tokens_neox': 2286, 'n_words': 453}