Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

js合成简谱 #29

Open
Jeffersondyj opened this issue Jan 9, 2020 · 0 comments
Open

js合成简谱 #29

Jeffersondyj opened this issue Jan 9, 2020 · 0 comments

Comments

@Jeffersondyj
Copy link
Owner

Jeffersondyj commented Jan 9, 2020

window.AudioContext = window.AudioContext || window.webkitAudioContext;

(function () {
var timerId = -1;
var MUSIC_KEYS = [
    196.00, 220.00, 246.94, 261.63, 293.66, 329.63, 349.23,
    392.00, 440.00, 493.88, 523.25, 587.33, 659.25, 698.46,
    783.99, 880.00, 987.77, 1046.50
];

window.stopAudio = function () {
    if (timerId >= 0) {
        clearInterval(timerId);
        timerId = -1;
    }
};

function getMusic() {
    var arr = [
        '12315 66865 668 565 653531231  ', // 我去上学校
        '5353531 24325  5353531 24321  2244315 24325  5353531 24321  ', // 粉刷匠
        '3 1 331 33565  6665444 23212  3 1 3 1 33566  8 556 3 21235  8 556 3 21231  ', // 数鸭子
        '123 45432  32345  123 45432  34321 ', // 一朵玫瑰花
        '1 3 531 5321265 3 5 8a985565888 3 21235586532111 ', // 小母鸡
        '334554321123322 334554321123211', // 欢乐颂
        '5854321 112331345  5854352 43265 231', // 我爱北京天安门
        '89a58aa 989cccc 8788888 7878765 5566666 5353598 5aaabc88a9', // 学猫叫
        'a8966 acaca 67865  5 aca68 9998a 8 6' // 芒种
    ];
    return arr[Math.floor(Math.random() * arr.length)];
}

window.playAudio = function (options) {
    if (!window.AudioContext) {
        console.log('当前浏览器不支持Web Audio API');
        return;
    }
    options = options || {};

    var arrFrequency = [];
    var music = getMusic().split('');
    var offset = 6;
    for (var i = 0; i < music.length; ++i) {
        music[i] = parseInt(music[i], 16);
        music[i] > 11 && (offset = -1); // 音域太高,必须降一个key
    }
    for (var i = 0; i < music.length; ++i) {
        arrFrequency.push(isNaN(music[i]) ? ' ' : MUSIC_KEYS[music[i] + offset]);
    }

    // 创建新的音频上下文接口
    var audioCtx = new AudioContext();
    var start = 0;
    stopAudio();
    timerId = setInterval(function () {
        var frequency = arrFrequency[start]; // 当前频率
        if (!frequency) { // 播放结束
            if (!options.isCircle) { // 非循环播放就停止
                stopAudio();
                return;
            }
            start = 0; // 否则轮播
            frequency = arrFrequency[start];
        }
        start++;
        if (frequency === ' ') { // 空格表示节奏停顿
            return;
        }

        // 创建一个OscillatorNode,它表示一个周期性波形(振荡),基本上来说创造了一个音调
        var oscillator = audioCtx.createOscillator();
        // 创建一个GainNode,它可以控制音频的总音量
        var gainNode = audioCtx.createGain();
        // 把音量,音调和终节点进行关联
        oscillator.connect(gainNode);
        // audioCtx.destination返回AudioDestinationNode对象,表示当前audio context中所有节点的最终节点,一般表示音频渲染设备
        gainNode.connect(audioCtx.destination);
        // 指定音调的类型,single|square|triangle|sawtooth
        oscillator.type = options.playType || 'triangle';
        // 设置当前播放声音的频率,也就是最终播放声音的调调
        oscillator.frequency.value = frequency;
        // 当前时间设置音量为0
        gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
        // 0.01秒后音量为1
        gainNode.gain.linearRampToValueAtTime(1, audioCtx.currentTime + 0.01);
        // 音调从当前时间开始播放
        oscillator.start(audioCtx.currentTime);
        // 1秒内声音慢慢降低,是个不错的停止声音的方法
        gainNode.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 1);
        // 1秒后完全停止声音
        oscillator.stop(audioCtx.currentTime + 1);
    }, options.interval || 250);
};
})();

// 调用
window.playAudio();
window.playAudio({isCircle: true}); // 循环播放
window.playAudio({interval: 167}); // 六分之一节拍
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant