CoolSoup is a React + TypeScript + Vite application that generates visual patterns and converts them to audio through spectral synthesis. Features multiple image generators (Tixy expressions, geometric tiles, external APIs) and an advanced audio synthesis engine that treats images as spectrograms.
79 lines
2.2 KiB
TypeScript
79 lines
2.2 KiB
TypeScript
import type { TixyExpression, TixyRenderOptions, TixyResult } from '../core/types'
|
|
import { evaluateTixyExpression } from '../core/evaluator'
|
|
|
|
export function renderTixyToCanvas(
|
|
expression: TixyExpression,
|
|
options: TixyRenderOptions
|
|
): TixyResult {
|
|
const {
|
|
width,
|
|
height,
|
|
time,
|
|
backgroundColor = '#000000',
|
|
foregroundColor = '#ffffff',
|
|
threshold = 0.3,
|
|
pixelSize = 1
|
|
} = options
|
|
|
|
const canvas = document.createElement('canvas')
|
|
canvas.width = width * pixelSize
|
|
canvas.height = height * pixelSize
|
|
|
|
const ctx = canvas.getContext('2d')!
|
|
const imageData = ctx.createImageData(width * pixelSize, height * pixelSize)
|
|
const data = imageData.data
|
|
|
|
const bgColor = hexToRgb(backgroundColor)
|
|
const fgColor = hexToRgb(foregroundColor)
|
|
|
|
for (let y = 0; y < height; y++) {
|
|
for (let x = 0; x < width; x++) {
|
|
const i = y * width + x
|
|
const value = evaluateTixyExpression(expression, time, i, x, y)
|
|
|
|
const color = Math.abs(value) > threshold
|
|
? {
|
|
r: Math.round(fgColor.r * (Math.sign(value) > 0 ? 1 : 0.8)),
|
|
g: Math.round(fgColor.g * (Math.sign(value) > 0 ? 1 : 0.8)),
|
|
b: Math.round(fgColor.b * (Math.sign(value) > 0 ? 1 : 0.8))
|
|
}
|
|
: bgColor
|
|
|
|
for (let py = 0; py < pixelSize; py++) {
|
|
for (let px = 0; px < pixelSize; px++) {
|
|
const actualX = x * pixelSize + px
|
|
const actualY = y * pixelSize + py
|
|
const pixelIndex = (actualY * width * pixelSize + actualX) * 4
|
|
|
|
data[pixelIndex] = color.r
|
|
data[pixelIndex + 1] = color.g
|
|
data[pixelIndex + 2] = color.b
|
|
data[pixelIndex + 3] = 255
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ctx.putImageData(imageData, 0, 0)
|
|
|
|
return {
|
|
imageData,
|
|
canvas
|
|
}
|
|
}
|
|
|
|
export function renderTixyToImageData(
|
|
expression: TixyExpression,
|
|
options: TixyRenderOptions
|
|
): ImageData {
|
|
return renderTixyToCanvas(expression, options).imageData
|
|
}
|
|
|
|
function hexToRgb(hex: string): { r: number; g: number; b: number } {
|
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
|
|
return result ? {
|
|
r: parseInt(result[1], 16),
|
|
g: parseInt(result[2], 16),
|
|
b: parseInt(result[3], 16)
|
|
} : { r: 0, g: 0, b: 0 }
|
|
} |