内容介绍
内容介绍
这实在Github分享的一个完全基于HTML5写成的X Y示波器软件,只有一个页面,文件也只有十几KB的大小,不仅支持双通道波形的显示,而且可以做频谱分析。信号源就用电脑或手机的麦克风。
此项目的Github链接地址
演示页面地址
它可以接受来自“麦克风”或“立体声混音”来源的实时输入。
它有三种模式:
- X Y,在此模式下左输入通道影响X轴,右输入通道影响Y轴,需要立体输入才能正确地绘制图像,否则它只绘制一条对角线,因为左和右是相同的,当收到警告时,你需要允许浏览器访问你的麦克风。
- 波形
- 频谱
在左通道播放正弦波,在右通道播放余弦波会画一个圆。
在Windows 10和微软Edge浏览器上工作得最好。
目前我无法让Chrome正确地分割左右通道,firefox似乎有一些我无法重写的AGC。您的设置可能没有这些问题。
在windows上操作方式:
- 在windows启动按钮附近的Cortana输入中打开“隐私”设置。
- 允许Microsoft Edge访问麦克风
- 在windows启动按钮附近的Cortana输入框中打开“声音”设置。
- 管理“录音”设备选择所需的音频输入,首选立体声输入。
- 刷新Edge浏览器的示波器页面,按下“开始”按钮,允许网站访问您的麦克风。
- 使一些噪音
您可以观看这个视频,以看到相同的模式,绘制在X Y视图,正如在视频中绘制的。图像使用可听见的声波在应用程序窗口之间传输。甚至可以在有空气隙的设备上工作。
要在windows中获得立体声输入,最好使用“立体声混音”选项设置为录音设备声音选项中的默认设备,并确保它的水平设置为100以获得最佳效果。
如果“立体声混合”选项不可见,右键单击设备区域,勾选“显示禁用设备”和“显示断开连接的设备”。
如果“立体声混音”仍然不可见,您可能需要从RealTek网站更新RealTek高清音频驱动程序。
如果所有设置都正确,那么从桌面播放合成器音乐将在显示中产生图案。
代码如下:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=980;initial-scale=1.0">
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />
<title>X Y Oscilloscope by seanwasere ytbe</title>
<style>
BODY {
margin: 0px;
padding: 0px;
font-family: Arial, Helvetica, sans-serif;
background-color: black;
color: black;
font-size: 17px;
overflow: hidden;
}
#scope {
position: absolute;
top: 0px;
left: 0px;
width: 1024px;
height: 1024px;
}
.startButton {
width: 100%;
height: 50px;
background-color: orangered;
border: 1px solid;
color: black;
font-size: 32px;
cursor: pointer;
}
.modal {
display: block;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.6);
}
.modal-content {
background-color: #dddddd;
margin: 12% auto;
padding: 20px;
border: 1px solid #888;
width: 50%;
}
.modal-footer {
text-align: center;
}
#modeOptions {
position: absolute;
top: 50px;
left: 10px;
color: white;
}
#LeftRightChannels {
position: absolute;
top: 90px;
left: 10px;
color: white;
display: none;
}
#XYFlipOptions {
position: absolute;
top: 90px;
left: 10px;
color: white;
display: block;
}
.bordered {
padding: 4px;
margin-right: 20px;
border: 1px solid gray;
}
#header {
position: absolute;
top: 10px;
left: 10px;
color: greenyellow;
}
#header a {
color: hotpink;
}
</style>
</head>
<body>
<canvas id='scope' width='1024' height='1024'></canvas>
<a href="https://github.com/Sean-Bradley/Oscilloscope">
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png"
alt="Fork me on GitHub">
</a>
<span id="header">
Tutorial at
<a href="https://www.youtube.com/watch?v=JrOP-RJ5p1I" target="_blank">Pictures from Sound using an Oscilloscope and Fruityloops FL Studio</a>
</span>
<span id="modeOptions">Mode:
<label class="bordered">
<input type="radio" name="rdoDisplayMode" id="0" onclick="setXYMode(0);" checked/>X Y</label>
<label class="bordered">
<input type="radio" name="rdoDisplayMode" id="1" onclick="setXYMode(1);" />Waveform</label>
<label class="bordered">
<input type="radio" name="rdoDisplayMode" id="1" onclick="setXYMode(2);" />Spectrum</label>
</span>
<span id="LeftRightChannels">
<label class="bordered">
<input type="checkbox" onchange="toggleLeft();" checked />Left Channel
</label>
<label class="bordered">
<input type="checkbox" onchange="toggleRight();" checked />Right Channel
</label>
</span>
<span id="XYFlipOptions">
<label class="bordered">
<input type="checkbox" onchange="changeflipX();" checked />Flip X
</label>
<label class="bordered">
<input type="checkbox" onchange="changeflipY();" checked />Flip Y
</label>
</span>
<div id="myModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h2>X Y Oscilloscope by seanwasere ytbe</h2>
</div>
<div class="modal-body">
<p>The X Y Oscilloscope uses Stereo Input.</p>
<p>Left Input channel affects X axis and right input channel affects Y axis.</p>
<p>Playing sine wave in left channel and cosine wave in right channel draws a circle.</p>
<button class="startButton" onclick="connectAudioAPI(); ">START</button>
<p>Works Best with Windows 10 and Edge browser (it's true).
<ul>
<li>Open 'Privacy' Settings from the Cortana input.</li>
<li>Allow Microsoft Edge to access Microphone</li>
<li>Open 'Sound' settings from the Cortana input box.</li>
<li>Manage 'Recording Devices' to select desired audio input, stero input preferred.</li>
<li>Refresh Oscilloscope Page in Edge Browser, Press 'START' button and allow website to access your
microphone.
</li>
<li>Make some noise</li>
</ul>
</p>
<p>
Tutorial of the Oscillioscope setup and drawing shapes with sound
<br/>
<a href="https://www.youtube.com/watch?v=JrOP-RJ5p1I" target="_blank">
<img src="https://img.youtube.com/vi/JrOP-RJ5p1I/0.jpg">
</a>
</p>
<p>Source code at
<a href="https://github.com/Sean-Bradley/Oscilloscope">https://github.com/Sean-Bradley/Oscilloscope</a>
</p>
<p>Written by
<a href="https://youtube.com/seanwasere " target="_blank">SeanWasEre Youtube</a>
</p>
</div>
</div>
</div>
<br/>
<script lang="javascript ">
var AudioContext = window.AudioContext || window.webkitAudioContext || false;
var XYMode = 0;
var connected = false;
var context;
var currentStream;
var mediaSource, mediaBuffer, remoteDestination;
var analyser1;
var analyser2;
var splitter;
var javascriptNode;
function setXYMode(b) {
if (b === 0) {
XYMode = 0;
document.getElementById("XYFlipOptions").style.display = "block";
document.getElementById("LeftRightChannels").style.display = "none";
analyser1.fftSize = 4096;
analyser2.fftSize = 4096;
} else if (b === 1) {
XYMode = 1;
document.getElementById("XYFlipOptions").style.display = "none";
document.getElementById("LeftRightChannels").style.display = "block";
analyser1.fftSize = 2048;
analyser2.fftSize = 2048;
} else {
XYMode = 2;
document.getElementById("XYFlipOptions").style.display = "none";
document.getElementById("LeftRightChannels").style.display = "block";
analyser1.fftSize = 2048;
analyser2.fftSize = 2048;
}
}
var leftChannel = true;
var rightChannel = true;
function toggleLeft() {
leftChannel = !leftChannel;
}
function toggleRight() {
rightChannel = !rightChannel;
}
function connectAudioAPI() {
try {
context = new AudioContext();
analyser1 = context.createAnalyser();
analyser1.fftSize = 4096;
analyser2 = context.createAnalyser();
analyser2.fftSize = 4096;
splitter = context.createChannelSplitter();
javascriptNode = context.createScriptProcessor(2048, 1, 1);
connectInput();
} catch (e) {
alert(e);
}
}
function connectInput() {
navigator.mediaDevices.getUserMedia({ audio: true })
.then(function (mediaStream) {
gotStream(mediaStream);
}).catch(function (e) {
alert("In connectInput : " + e);
});
}
function gotStream(stream) {
try {
mediaSource = context.createMediaStreamSource(stream);
mediaSource.connect(splitter);
splitter.connect(analyser1, 0, 0);
splitter.connect(analyser2, 1, 0);
document.getElementById("myModal").style.display = "none";
resizeCanvas();
javascriptNode.connect(context.destination);
javascriptNode.onaudioprocess = function () {
drawScope();
}
} catch (e) {
alert("In gotStream : " + e);
}
}
var ctx = document.getElementById('scope').getContext('2d');
var width = 1024;
var height = 1024;
var canvasData = ctx.getImageData(0, 0, width, height);
var canvasBlankData = ctx.getImageData(0, 0, width, height);
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
document.getElementById('scope').style.width = window.innerWidth + "px";
document.getElementById('scope').style.height = window.innerHeight + "px";
}
var flipX = false;
var flipY = false;
var scaleX = 4;
var scaleY = 4;
function drawScope() {
var timeData1 = new Uint8Array(analyser1.frequencyBinCount);
var timeData2 = new Uint8Array(analyser2.frequencyBinCount);
if (XYMode === 0) {
analyser1.getByteTimeDomainData(timeData1);
analyser2.getByteTimeDomainData(timeData2);
ctx.fillStyle = 'rgba(0, 0, 0, .1)';
ctx.fillRect(0, 0, width, height);
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = 'rgb(0, 128, 255)';
ctx.beginPath();
if (flipX && flipY) {
for (var x = 0; x < timeData1.length; x++) {
ctx.lineTo(width - timeData1[x] * scaleX, timeData2[x] * scaleY);
}
} else if (flipX && !flipY) {
for (var x = 0; x < timeData1.length; x++) {
ctx.lineTo(width - timeData1[x] * scaleX, height - timeData2[x] * scaleY);
}
} else if (!flipX && flipY) {
for (var x = 0; x < timeData1.length; x++) {
ctx.lineTo(timeData1[x] * scaleX, timeData2[x] * scaleY);
}
} else {
for (var x = 0; x < timeData1.length; x++) {
ctx.lineTo(timeData1[x] * scaleX, height - timeData2[x] * scaleY);
}
}
ctx.stroke();
} else {
if (XYMode === 1) {
analyser1.getByteTimeDomainData(timeData1);
analyser2.getByteTimeDomainData(timeData2);
ctx.fillStyle = "rgb(0, 0, 0) ";
ctx.fillRect(0, 0, 1024, 1024);
ctx.strokeStyle = 'rgb(255, 128, 0)';
ctx.lineWidth = 3;
if (leftChannel && rightChannel) {
ctx.beginPath();
for (var x = 0; x < 1024; x++) {
ctx.lineTo(x, 512 - (timeData1[x] * 2));
}
ctx.stroke();
ctx.beginPath();
for (var x = 0; x < 1024; x++) {
ctx.lineTo(x, 1024 - (timeData2[x] * 2));
}
ctx.stroke();
} else if (leftChannel && !rightChannel) {
ctx.beginPath();
for (var x = 0; x < 1024; x++) {
ctx.lineTo(x, 1024 - (timeData1[x] * 4));
}
ctx.stroke();
} else if (!leftChannel && rightChannel) {
ctx.beginPath();
for (var x = 0; x < 1024; x++) {
ctx.lineTo(x, 1024 - (timeData2[x] * 4));
}
ctx.stroke();
}
} else {
analyser1.getByteFrequencyData(timeData1);
analyser2.getByteFrequencyData(timeData2);
ctx.fillStyle = "rgb(0, 0, 0) ";
ctx.fillRect(0, 0, 1024, 1024);
ctx.strokeStyle = 'rgb(128, 0, 256)';
ctx.lineWidth = 6;
if (leftChannel && rightChannel) {
ctx.beginPath();
for (var x = 0; x < 512; x++) {
ctx.lineTo(x * 2, 500 - (timeData1[x] * 2));
}
ctx.stroke();
ctx.beginPath();
for (var x = 0; x < 512; x++) {
ctx.lineTo(x * 2, 1012 - (timeData2[x] * 2));
}
ctx.stroke();
} else if (leftChannel && !rightChannel) {
ctx.beginPath();
for (var x = 0; x < 512; x++) {
ctx.lineTo(x * 2, 1012 - (timeData1[x] * 4));
}
ctx.stroke();
} else if (!leftChannel && rightChannel) {
ctx.beginPath();
for (var x = 0; x < 512; x++) {
ctx.lineTo(x * 2, 1012 - (timeData2[x] * 4));
}
ctx.stroke();
}
}
}
}
function changeflipX(e) {
flipX = !flipX;
}
function changeflipY(e) {
flipY = !flipY;
}
</script>
</body>
</html>
团队介绍
Sean-Bradley
团队成员
Sean-Bradley
来自Github上的一位分享者,他的Youtube:https://www.youtube.com/user/seanwasere, Github页面:https://github.com/Sean-Bradley
评论
0 / 100
查看更多