This commit is contained in:
Robin Davies
2022-03-12 02:12:34 -05:00
parent 733415ab1f
commit 7a2f4ee9a4
9 changed files with 486 additions and 29 deletions
+6 -3
View File
@@ -3,8 +3,7 @@
[v0.1.5-beta](docs/download.md)
Use your Raspberry Pi as a guitar effects pedal. PiPedal allows you to control and configure your guitar effects via a web interface, using your phone, tablet, or computer.
Use your Raspberry Pi as a guitar effects pedal. Configure and control PiPedal with your phone or tablet.
PiPedal running on a Raspberry Pi 4 provides stable super-low-latency audio via external USB audio devices, or internal Raspberry Pi audio hats.
PiPedal's user interface has been specifically designed to work well on small form-factor touch devices like phones or tablets. Clip a phone or tablet on your microphone stand on stage, and you're ready to play! Or connect via a desktop browser, for a slightly more luxurious experience. The PiPedal user-interface adapts to the screen size and orientation of your device, providing easy control of your guitar effects across a broad variety devices and screen sizes.
@@ -15,7 +14,11 @@ PiPedal provides a pre-installed selection of LV2 plugins from the ToobAmp colle
If your USB audio adapter has midi connectors, you can use midi devices (keyboards or midi floor boards) to control PiPedal while performing. A simple interface allows you to select how you would like to bind PiPedal controls to midi messages.
![Screenshot](docs/PiPedalScreenshots.png)
{% include gallery.html %}
<!-- ![Screenshot](docs/gallery/jazz.png) -->
----
%nbsp;
### [System Requirements](docs/SystemRequirements.md)
### [Installing PiPedal](docs/Installing.md)
+223
View File
@@ -0,0 +1,223 @@
<script>
{
let images = [
"jazz.png",
"thunder.png",
"midi-bindings.png",
"hotspot.png"
];
let captions = [
"PiPedal web interface.",
"Flexible effect routing.",
"Bind controls to midi messages.",
"Easy Wi-Fi hotspot configuration."
];
let maxWidth = 680;
let aspectX = 952;
let aspectY = 648;
let borderWidth = 0;
let galleryPath = "docs/gallery/";
let width ;
let height;
let frameWidth ;
let frameHeight;
let galleryFrame = 0;
let calculateWidth = function () {
width = Math.min(maxWidth, window.innerWidth * 0.8);
height = width * aspectY / aspectX;
frameWidth = width + borderWidth * 2;
frameHeight = height + borderWidth * 2;
}
calculateWidth();
let galleryX = 0;
let galleryLastAnimationCallback = 0;
let galleryAnimationStart;
let galleryAnimationStep;
let galleryAnimationData;
let gallerySlideAnimation = (fromFrame, toFrame) => {
if (galleryLastAnimationCallback !== 0) {
window.cancelAnimationFrame(galleryLastAnimationCallback);
galleryLastAnimationCallback = 0;
}
let targetX = (-toFrame * frameWidth);
galleryAnimationData = {
x0: galleryX,
x1: targetX,
element: document.getElementById('gallery_slideFrame')
};
galleryAnimationStart = undefined;
galleryAnimationStep = function (timeStamp) {
if (!galleryAnimationStart) {
galleryAnimationStart = timeStamp;
}
let ms = timeStamp - galleryAnimationStart;
const MS_LEN = 300;
if (ms > MS_LEN) {
ms = MS_LEN;
}
let x = (galleryAnimationData.x1 - galleryAnimationData.x0) * ms / MS_LEN + galleryAnimationData.x0;
galleryAnimationData.element.style.left = x + "px";
if (ms < MS_LEN) {
galleryLastAnimationCallback = window.requestAnimationFrame(galleryAnimationStep);
galleryX = x;
} else {
galleryX = galleryAnimationData.x1;
galleryAnimationData = undefined;
galleryLastAnimationCallback = 0;
galleryAnimationStep = undefined;
let captionElement = document.getElementById("gallery_caption");
captionElement.innerText = captions[galleryFrame];
}
}
galleryLastAnimationCallback = window.requestAnimationFrame(galleryAnimationStep);
}
let galleryScrollLeft = () => {
let startFrame = galleryFrame;
galleryFrame = galleryFrame - 1;
if (galleryFrame < 0) {
galleryFrame = images.length - 1;
}
gallerySlideAnimation(startFrame, galleryFrame);
}
let galleryScrollRight = () => {
let startFrame = galleryFrame;
galleryFrame = galleryFrame + 1;
if (galleryFrame >= images.length) {
galleryFrame = 0;
}
gallerySlideAnimation(startFrame, galleryFrame);
}
let galleryFrameElement;
let galleryOnClick = (e) => {
let rcClient = galleryFrameElement.getBoundingClientRect();
let x = e.clientX - rcClient.x;
if (x < 80) {
galleryScrollLeft();
} else if (x > frameWidth - 80) {
galleryScrollRight();
}
}
let galleryMouseEnter = (e) => {
let galleryArrows = document.getElementById('galleryArrows');
galleryArrows.style.opacity = 1.0;
}
let galleryMouseLeave = (e) => {
let galleryArrows = document.getElementById('galleryArrows');
galleryArrows.style.opacity = 0;
}
let galleryWindowResize = function (e) {
calculateWidth();
let frameWidthPx = frameWidth + "px";
let frameHeightPx = frameHeight + "px";
let widthPx = width + "px";
let heightPx = height + "px";
galleryFrameElement.style.width = frameWidthPx;
galleryFrameElement.style.height = frameHeightPx;
let slideFrame = galleryFrameElement.children[0];
slideFrame.style.width = (frameWidth * images.length) + "px";
slideFrame.style.height = frameHeightPx;
let galleryArrows = galleryFrameElement.children[1];
galleryArrows.style.width = frameWidthPx;
galleryArrows.style.height = frameHeightPx;
let imagesElements = slideFrame.children;
for (let i = 0; i < imagesElements.length; ++i) {
let child = imagesElements[i];
child.style.width = widthPx;
child.style.height = heightPx;
child.style.left = (frameWidth * i) + "px";
}
galleryX = -galleryFrame*frameWidth;
slideFrame.style.left = galleryX + "px";
document.getElementById('gallery_caption_frame').style.width = frameWidthPx;
}
// gallery frame.
document.writeln("<div id='galleryFrame' style='margin-left: 20px; width: "
+ frameWidth
+ "px; height: "
+ frameHeight
+ "px; overflow: hidden; position: relative;' >");
{
// carrier for sliding images.
document.writeln("<div id='gallery_slideFrame' style='position: absolute; width: "
+ (frameWidth * images.length)
+ "px; height: "
+ (frameHeight)
+ "px; background: #0; left: 0px' >"
);
{
// the images.
for (let i = 0; i < images.length; ++i) {
document.writeln("<img src='"
+ (galleryPath + images[i])
+ "' style='border: black " + borderWidth + "px solid; width: "
+ (width)
+ "px;height: "
+ height
+ "px; object-fit: contain; position: absolute; top: 0px; left: "
+ (i * frameWidth)
+ "px' />");
}
}
document.writeln("</div>");
document.writeln("<div id='galleryArrows' style='position: absolute; width: "
+ frameWidth + "px; height: " + frameHeight
+ "px; left: 0px; top: 0px; opacity: 0.0;"
+ " display: flex; flex-flow: row none; justify-content: space-between;align-items: end; padding:20'>");
{
document.writeln("<div><span style='font-size: 52px;color: #444;'>◄</span></div>");
document.writeln("<div><span style='font-size: 52px;color: #444;'>►</span></div>");
}
document.writeln("</div>");
}
document.writeln("</div>");
document.writeln("<div id='gallery_caption_frame' style='margin-left: 20px; width: " + frameWidth + "px; display: flex; flex-flow: row nowrap; justify-content: center; background: #666;'>");
document.writeln("<div> <span id='gallery_caption' style='font-size: 0.9em; font-style: italic; color: #FFF;'> "
+ captions[0] + "</span></div></div>");
let galleryOnLoaded = () => {
galleryFrameElement = document.getElementById('galleryFrame');
galleryFrameElement.addEventListener('click', galleryOnClick, true);
galleryFrameElement.addEventListener('mouseenter', galleryMouseEnter);
galleryFrameElement.addEventListener('mouseleave', galleryMouseLeave);
}
window.addEventListener('load', function (e) {
galleryOnLoaded(e);
}, false);
window.addEventListener('resize', galleryWindowResize);
}
</script>
-26
View File
@@ -1,26 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ page.title }}</title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<nav>
<a href="/pipedal">
<img src="/pipedal/docs/PiPedal-logo.png" style="height: 16px" />
</a>
<a href="/blog/">Blog</a>
</nav>
<h1>{{ page.title }}</h1>
<section>
{{ content }}
</section>
<footer>
&copy; to me
</footer>
</body>
</html>
+223
View File
@@ -0,0 +1,223 @@
<script>
{
let images = [
"jazz.png",
"thunder.png",
"midi-bindings.png",
"hotspot.png"
];
let captions = [
"PiPedal web interface.",
"Flexible effect routing.",
"Bind controls to midi messages.",
"Easy Wi-Fi hotspot configuration."
];
let maxWidth = 680;
let aspectX = 952;
let aspectY = 648;
let borderWidth = 0;
let galleryPath = "gallery/";
let width ;
let height;
let frameWidth ;
let frameHeight;
let galleryFrame = 0;
let calculateWidth = function () {
width = Math.min(maxWidth, window.innerWidth * 0.8);
height = width * aspectY / aspectX;
frameWidth = width + borderWidth * 2;
frameHeight = height + borderWidth * 2;
}
calculateWidth();
let galleryX = 0;
let galleryLastAnimationCallback = 0;
let galleryAnimationStart;
let galleryAnimationStep;
let galleryAnimationData;
let gallerySlideAnimation = (fromFrame, toFrame) => {
if (galleryLastAnimationCallback !== 0) {
window.cancelAnimationFrame(galleryLastAnimationCallback);
galleryLastAnimationCallback = 0;
}
let targetX = (-toFrame * frameWidth);
galleryAnimationData = {
x0: galleryX,
x1: targetX,
element: document.getElementById('gallery_slideFrame')
};
galleryAnimationStart = undefined;
galleryAnimationStep = function (timeStamp) {
if (!galleryAnimationStart) {
galleryAnimationStart = timeStamp;
}
let ms = timeStamp - galleryAnimationStart;
const MS_LEN = 300;
if (ms > MS_LEN) {
ms = MS_LEN;
}
let x = (galleryAnimationData.x1 - galleryAnimationData.x0) * ms / MS_LEN + galleryAnimationData.x0;
galleryAnimationData.element.style.left = x + "px";
if (ms < MS_LEN) {
galleryLastAnimationCallback = window.requestAnimationFrame(galleryAnimationStep);
galleryX = x;
} else {
galleryX = galleryAnimationData.x1;
galleryAnimationData = undefined;
galleryLastAnimationCallback = 0;
galleryAnimationStep = undefined;
let captionElement = document.getElementById("gallery_caption");
captionElement.innerText = captions[galleryFrame];
}
}
galleryLastAnimationCallback = window.requestAnimationFrame(galleryAnimationStep);
}
let galleryScrollLeft = () => {
let startFrame = galleryFrame;
galleryFrame = galleryFrame - 1;
if (galleryFrame < 0) {
galleryFrame = images.length - 1;
}
gallerySlideAnimation(startFrame, galleryFrame);
}
let galleryScrollRight = () => {
let startFrame = galleryFrame;
galleryFrame = galleryFrame + 1;
if (galleryFrame >= images.length) {
galleryFrame = 0;
}
gallerySlideAnimation(startFrame, galleryFrame);
}
let galleryFrameElement;
let galleryOnClick = (e) => {
let rcClient = galleryFrameElement.getBoundingClientRect();
let x = e.clientX - rcClient.x;
if (x < 80) {
galleryScrollLeft();
} else if (x > frameWidth - 80) {
galleryScrollRight();
}
}
let galleryMouseEnter = (e) => {
let galleryArrows = document.getElementById('galleryArrows');
galleryArrows.style.opacity = 1.0;
}
let galleryMouseLeave = (e) => {
let galleryArrows = document.getElementById('galleryArrows');
galleryArrows.style.opacity = 0;
}
let galleryWindowResize = function (e) {
calculateWidth();
let frameWidthPx = frameWidth + "px";
let frameHeightPx = frameHeight + "px";
let widthPx = width + "px";
let heightPx = height + "px";
galleryFrameElement.style.width = frameWidthPx;
galleryFrameElement.style.height = frameHeightPx;
let slideFrame = galleryFrameElement.children[0];
slideFrame.style.width = (frameWidth * images.length) + "px";
slideFrame.style.height = frameHeightPx;
let galleryArrows = galleryFrameElement.children[1];
galleryArrows.style.width = frameWidthPx;
galleryArrows.style.height = frameHeightPx;
let imagesElements = slideFrame.children;
for (let i = 0; i < imagesElements.length; ++i) {
let child = imagesElements[i];
child.style.width = widthPx;
child.style.height = heightPx;
child.style.left = (frameWidth * i) + "px";
}
galleryX = -galleryFrame*frameWidth;
slideFrame.style.left = galleryX + "px";
document.getElementById('gallery_caption_frame').style.width = frameWidthPx;
}
// gallery frame.
document.writeln("<div id='galleryFrame' style='margin-left: 20px; width: "
+ frameWidth
+ "px; height: "
+ frameHeight
+ "px; overflow: hidden; position: relative;' >");
{
// carrier for sliding images.
document.writeln("<div id='gallery_slideFrame' style='position: absolute; width: "
+ (frameWidth * images.length)
+ "px; height: "
+ (frameHeight)
+ "px; background: #0; left: 0px' >"
);
{
// the images.
for (let i = 0; i < images.length; ++i) {
document.writeln("<img src='"
+ (galleryPath + images[i])
+ "' style='border: black " + borderWidth + "px solid; width: "
+ (width)
+ "px;height: "
+ height
+ "px; object-fit: contain; position: absolute; top: 0px; left: "
+ (i * frameWidth)
+ "px' />");
}
}
document.writeln("</div>");
document.writeln("<div id='galleryArrows' style='position: absolute; width: "
+ frameWidth + "px; height: " + frameHeight
+ "px; left: 0px; top: 0px; opacity: 0.0;"
+ " display: flex; flex-flow: row none; justify-content: space-between;align-items: end; padding:20'>");
{
document.writeln("<div><span style='font-size: 52px;color: #444;'>◄</span></div>");
document.writeln("<div><span style='font-size: 52px;color: #444;'>►</span></div>");
}
document.writeln("</div>");
}
document.writeln("</div>");
document.writeln("<div id='gallery_caption_frame' style='margin-left: 20px; width: " + frameWidth + "px; display: flex; flex-flow: row nowrap; justify-content: center; background: #666;'>");
document.writeln("<div> <span id='gallery_caption' style='font-size: 0.9em; font-style: italic; color: #FFF;'> "
+ captions[0] + "</span></div></div>");
let galleryOnLoaded = () => {
galleryFrameElement = document.getElementById('galleryFrame');
galleryFrameElement.addEventListener('click', galleryOnClick, true);
galleryFrameElement.addEventListener('mouseenter', galleryMouseEnter);
galleryFrameElement.addEventListener('mouseleave', galleryMouseLeave);
}
window.addEventListener('load', function (e) {
galleryOnLoaded(e);
}, false);
window.addEventListener('resize', galleryWindowResize);
}
</script>
+34
View File
@@ -0,0 +1,34 @@
let images = [
"jazz.png",
"thunder.png",
"midi-bindings.png",
"hotspot.png"
];
let width=480;
let height = 320;
let borderWidth = 2;
let galleryPath = "gallery/";
document.write("<div style='width: "
+ (width+2*boderWidth)
+ "px; height: "
+(height+2*borderWidth)
+ "; overflow: hidden; position: relative'>");
{
document.write("<div id='slideFrame' >");
{
for (let i = 0; i < images.length; ++i) {
document.write("<img src='"
+ (galleryPath + images[i])
+ "' style='border: black " + borderWidth + "px solid; width: "
+ (width)
+ "px;height: "
+ height
+"px; position: absolute; top: 0px; left: "
+ (i*width*i)
+ "px' />");
}
}
document.write("</div>");
}
document.write("</div>");
Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB