129 lines
3.1 KiB
TypeScript
129 lines
3.1 KiB
TypeScript
import { PrismaClient } from "@prisma/client";
|
|
import LCD from "raspberrypi-liquid-crystal";
|
|
import fs from "node:fs";
|
|
import * as WavFileDecoder from "wav-file-decoder";
|
|
|
|
const timer = (ms: number) => new Promise((res) => setTimeout(res, ms));
|
|
|
|
const prisma = new PrismaClient();
|
|
const getStanza = async (register: string) => {
|
|
const stanzaCount = await prisma.stanza.count({ where: { register } });
|
|
const skip = Math.floor(Math.random() * stanzaCount);
|
|
const randomStanza = await prisma.stanza.findMany({
|
|
skip: skip,
|
|
take: 1,
|
|
where: {
|
|
register,
|
|
},
|
|
});
|
|
|
|
if (!randomStanza || !randomStanza[0].text) {
|
|
console.log(
|
|
register,
|
|
stanzaCount,
|
|
skip,
|
|
randomStanza,
|
|
"no stanza found in db"
|
|
);
|
|
// try one more time
|
|
const anotherStanzaTry = await prisma.stanza.findMany({
|
|
skip: skip,
|
|
take: 1,
|
|
where: {
|
|
register,
|
|
},
|
|
});
|
|
return anotherStanzaTry[0].text as string;
|
|
}
|
|
|
|
return randomStanza[0].text as string;
|
|
};
|
|
|
|
// Play portal wave PCM data and set bands
|
|
// This file has been downsampled to 1000hz (1,000 samples per second)
|
|
const fileData = fs.readFileSync("/home/grace/portal/blackportal1000.wav");
|
|
const wavFileInfo = WavFileDecoder.getWavFileInfo(fileData);
|
|
const audioData = WavFileDecoder.decodeWavFile(fileData);
|
|
const totalSamples = wavFileInfo.chunkInfo.filter(
|
|
(ci) => ci.chunkId === "data"
|
|
)[0].dataLength;
|
|
|
|
let sample = 0;
|
|
let register = "high";
|
|
let count = 0;
|
|
|
|
setInterval(() => {
|
|
const absSample = Math.abs(audioData.channelData[0][count]);
|
|
if (count == totalSamples - 1) {
|
|
count = 0;
|
|
console.log("total samples reached");
|
|
} else {
|
|
count++;
|
|
}
|
|
register = "high";
|
|
if (absSample < 0.01) {
|
|
register = "mid";
|
|
}
|
|
if (absSample < 0.001) {
|
|
register = "low";
|
|
}
|
|
|
|
sample = absSample;
|
|
console.log(count);
|
|
}, 1);
|
|
|
|
// Setup lcd screen
|
|
const lcd = new LCD(1, 0x27, 16, 2);
|
|
lcd.beginSync();
|
|
lcd.clearSync();
|
|
|
|
const TICK = 250;
|
|
const WAIT = 10;
|
|
|
|
// Play bottom line
|
|
const tag =
|
|
" Black Portal 4856 E Davison, Detroit ";
|
|
let tagCharacterLocation = 0;
|
|
|
|
setInterval(() => {
|
|
lcd.printLineSync(1, " ");
|
|
setTimeout(() => {
|
|
lcd.printLineSync(1, tag);
|
|
}, WAIT);
|
|
|
|
tagCharacterLocation++;
|
|
if (tagCharacterLocation > tag.length) {
|
|
tagCharacterLocation = 0;
|
|
}
|
|
}, TICK);
|
|
|
|
let characterLocation = 0;
|
|
let stanzaText = "";
|
|
let endBuffer = "";
|
|
let totalTicks = 0;
|
|
// Play top line
|
|
while (true) {
|
|
if (characterLocation == totalTicks) {
|
|
characterLocation = 0;
|
|
stanzaText = await getStanza(register);
|
|
endBuffer =
|
|
stanzaText.length > 16 ? "" : Array(16 - stanzaText.length).join(" ");
|
|
totalTicks = stanzaText.length + endBuffer.length;
|
|
}
|
|
if (!stanzaText) {
|
|
console.log("no stanza text in stanza scroller");
|
|
}
|
|
lcd.printLineSync(0, " ");
|
|
setTimeout(() => {
|
|
lcd.printLineSync(
|
|
0,
|
|
`${
|
|
totalTicks - characterLocation > 0
|
|
? Array(16 - characterLocation).join(" ")
|
|
: ""
|
|
}${stanzaText + endBuffer}`
|
|
);
|
|
}, WAIT);
|
|
await timer(TICK);
|
|
characterLocation++;
|
|
}
|