Skip to content

Commit

Permalink
lint
Browse files Browse the repository at this point in the history
  • Loading branch information
m1m0zzz committed Nov 11, 2023
1 parent 64b0e16 commit 35a4625
Show file tree
Hide file tree
Showing 24 changed files with 1,051 additions and 930 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ jobs:
steps:
- name: Deploy
id: deployment
uses: actions/deploy-pages@v2
uses: actions/deploy-pages@v2
20 changes: 10 additions & 10 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"cSpell.words": [
"browserconfig",
"controlslist",
"lightskyblue",
"MaruMinya",
"mimoz",
"nodownload",
"ondataavailable"
]
}
"cSpell.words": [
"browserconfig",
"controlslist",
"lightskyblue",
"MaruMinya",
"mimoz",
"nodownload",
"ondataavailable"
]
}
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# .Spectrum

dot spectrum is a pixel-art-like spectrum analyzer. w/ Web Audio API.

![preview](./preview.gif)


## Developing

Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
Expand All @@ -28,13 +28,15 @@ You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
## TODO
- ドット化サイズを1/nと、ピクセルサイズの両方で指定可能にする

- ドット化サイズを 1/n と、ピクセルサイズの両方で指定可能にする
- キャンバスの大きさ テンプレート
- Media Recorder
- mp4対応
- mp4 対応
- audio プレイヤー デザイン

## 📚 Tech Stack

- Canvas API
- Web Audio API
- PWA
Expand Down
4 changes: 2 additions & 2 deletions src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<link rel="stylesheet" href="%sveltekit.assets%/styles/modern-css-reset/reset.min.css">
<link rel="stylesheet" href="%sveltekit.assets%/styles/style.css">
<link rel="stylesheet" href="%sveltekit.assets%/styles/modern-css-reset/reset.min.css" />
<link rel="stylesheet" href="%sveltekit.assets%/styles/style.css" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
Expand Down
27 changes: 13 additions & 14 deletions src/lib/ffmpeg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,22 @@ import { createFFmpeg, fetchFile, type FFmpeg } from '@ffmpeg/ffmpeg';
// TODO: ログは dev環境のみで流す

const ffmpeg: FFmpeg = createFFmpeg({
log: true
log: true
});

export const load = async () => {
await ffmpeg.load();
}
await ffmpeg.load();
};

const VIDEO_KEY = "video";
const VIDEO_KEY = 'video';

// return: blob url
export const convertMp4 = async (file: File, outputName = "output.mp4") => {
ffmpeg.FS("writeFile", VIDEO_KEY, await fetchFile(file));
console.time("exec");
await ffmpeg.run("-i", VIDEO_KEY, outputName);
console.timeEnd("exec");
const data = ffmpeg.FS("readFile", outputName);

return URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
}

export const convertMp4 = async (file: File, outputName = 'output.mp4') => {
ffmpeg.FS('writeFile', VIDEO_KEY, await fetchFile(file));
console.time('exec');
await ffmpeg.run('-i', VIDEO_KEY, outputName);
console.timeEnd('exec');
const data = ffmpeg.FS('readFile', outputName);

return URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
};
16 changes: 8 additions & 8 deletions src/lib/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { browser } from "$app/environment";
import { init, register } from "svelte-i18n";
import { browser } from '$app/environment';
import { init, register } from 'svelte-i18n';

export const defaultLocale = "ja";
export const defaultLocale = 'ja';
export const languagesList = [
{ lang: "ja", name: "日本語" },
{ lang: "en", name: "English" }
{ lang: 'ja', name: '日本語' },
{ lang: 'en', name: 'English' }
];

register("ja", () => import("./locales/ja.json"));
register("en", () => import("./locales/en.json"));
register('ja', () => import('./locales/ja.json'));
register('en', () => import('./locales/en.json'));

init({
fallbackLocale: defaultLocale,
initialLocale: browser ? window.navigator.language : defaultLocale,
initialLocale: browser ? window.navigator.language : defaultLocale
});
64 changes: 32 additions & 32 deletions src/lib/i18n/locales/en.json
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
{
"usage": "Usage",
"usage_1": "Upload pixel art (png, jpg...)",
"usage_2": "Upload music (wav, mp3...)",
"usage_3": "Play music!",
"supported_version": "Supported Versions",
"upload_image": "Upload image file",
"upload_image_error": "Image is too large. Please pixelate. (Images of 256px x 256px or less can be specified.)",
"image_info": "Image size ( width: {width}px, height: {height}px )",
"is_pixelation": "Do you want to pixelate?",
"do_pixelation": " yes",
"do_not_pixelation": " no",
"upload_audio": "Upload audio file.",
"parameters_setting": "⚙️ Setting",
"parameters_window_size": "window size: ",
"parameters_custom": "custom",
"parameters_width": "width: ",
"parameters_height": "height: ",
"parameters_note": "NOTE: The value should be n times the number of pixels in the image to display it nicely",
"parameters_background": "background: ",
"parameters_fft_size": "FFT size: ",
"parameters_spectrum_type": "spectrum type: ",
"parameters_sensitivity": "sensitivity: ",
"parameters_grid_size": "grid size: ",
"parameters_smooth": "smooth: ",
"change_full_screen": "full screen mode",
"disabled_full_screen": "Full screen mode is not available",
"generate_video": "Generate video",
"generate_video_message": "Generating video... Please keep the screen open.",
"generate_video_error": "Upload your image and audio.",
"ffmpeg_error": "error: ffmpeg is not available.",
"download_video": "Download video"
}
"usage": "Usage",
"usage_1": "Upload pixel art (png, jpg...)",
"usage_2": "Upload music (wav, mp3...)",
"usage_3": "Play music!",
"supported_version": "Supported Versions",
"upload_image": "Upload image file",
"upload_image_error": "Image is too large. Please pixelate. (Images of 256px x 256px or less can be specified.)",
"image_info": "Image size ( width: {width}px, height: {height}px )",
"is_pixelation": "Do you want to pixelate?",
"do_pixelation": " yes",
"do_not_pixelation": " no",
"upload_audio": "Upload audio file.",
"parameters_setting": "⚙️ Setting",
"parameters_window_size": "window size: ",
"parameters_custom": "custom",
"parameters_width": "width: ",
"parameters_height": "height: ",
"parameters_note": "NOTE: The value should be n times the number of pixels in the image to display it nicely",
"parameters_background": "background: ",
"parameters_fft_size": "FFT size: ",
"parameters_spectrum_type": "spectrum type: ",
"parameters_sensitivity": "sensitivity: ",
"parameters_grid_size": "grid size: ",
"parameters_smooth": "smooth: ",
"change_full_screen": "full screen mode",
"disabled_full_screen": "Full screen mode is not available",
"generate_video": "Generate video",
"generate_video_message": "Generating video... Please keep the screen open.",
"generate_video_error": "Upload your image and audio.",
"ffmpeg_error": "error: ffmpeg is not available.",
"download_video": "Download video"
}
62 changes: 31 additions & 31 deletions src/lib/i18n/locales/ja.json
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
{
"usage": "使い方",
"usage_1": "ドット絵をアップ (png, jpg...)",
"usage_2": "音声をアップ (wav, mp3...)",
"usage_3": "音声を再生!",
"supported_version": "サポートされているバージョン",
"upload_image": "画像をアップロード",
"upload_image_error": "画像が大き過ぎます。ドット化してください。(256px × 256px以下の画像が指定可能です。)",
"image_info": "画像サイズ(幅: {width}px, 高さ: {height}px)",
"is_pixelation": "ドット化しますか?",
"do_pixelation": "する",
"do_not_pixelation": "しない",
"upload_audio": "音声をアップロード",
"parameters_setting": "⚙️ 設定",
"parameters_window_size": "画面サイズ: ",
"parameters_custom": "カスタム",
"parameters_width": "幅: ",
"parameters_height": "高さ: ",
"parameters_note": "※ ドット絵のピクセル数×n倍の値にすると、きれいに表示できます",
"parameters_background": "背景色: ",
"parameters_fft_size": "FFTサイズ: ",
"parameters_spectrum_type": "タイプ: ",
"parameters_sensitivity": "感度: ",
"parameters_grid_size": "グリッドサイズ: ",
"parameters_smooth": "スムーズ: ",
"change_full_screen": "全画面モードに切り替える",
"disabled_full_screen": "全画面モードが使用できません",
"generate_video": "動画を作成する",
"generate_video_message": "動画を作成中です... 画面を開いたままにしてください",
"generate_video_error": "画像と音声をアップロードしてください",
"ffmpeg_error": "エラー: ffmpegが使用できません",
"download_video": "動画をダウンロードする"
"usage": "使い方",
"usage_1": "ドット絵をアップ (png, jpg...)",
"usage_2": "音声をアップ (wav, mp3...)",
"usage_3": "音声を再生!",
"supported_version": "サポートされているバージョン",
"upload_image": "画像をアップロード",
"upload_image_error": "画像が大き過ぎます。ドット化してください。(256px × 256px以下の画像が指定可能です。)",
"image_info": "画像サイズ(幅: {width}px, 高さ: {height}px)",
"is_pixelation": "ドット化しますか?",
"do_pixelation": "する",
"do_not_pixelation": "しない",
"upload_audio": "音声をアップロード",
"parameters_setting": "⚙️ 設定",
"parameters_window_size": "画面サイズ: ",
"parameters_custom": "カスタム",
"parameters_width": "幅: ",
"parameters_height": "高さ: ",
"parameters_note": "※ ドット絵のピクセル数×n倍の値にすると、きれいに表示できます",
"parameters_background": "背景色: ",
"parameters_fft_size": "FFTサイズ: ",
"parameters_spectrum_type": "タイプ: ",
"parameters_sensitivity": "感度: ",
"parameters_grid_size": "グリッドサイズ: ",
"parameters_smooth": "スムーズ: ",
"change_full_screen": "全画面モードに切り替える",
"disabled_full_screen": "全画面モードが使用できません",
"generate_video": "動画を作成する",
"generate_video_message": "動画を作成中です... 画面を開いたままにしてください",
"generate_video_error": "画像と音声をアップロードしてください",
"ffmpeg_error": "エラー: ffmpegが使用できません",
"download_video": "動画をダウンロードする"
}
111 changes: 58 additions & 53 deletions src/lib/image.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,62 @@
export const toBase64 = (file: File) => new Promise<string>((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result as string);
reader.onerror = reject;
});

export const loadImage = (src: string) => new Promise<HTMLImageElement>((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = (e) => reject(e);
img.src = src;
});
export const toBase64 = (file: File) =>
new Promise<string>((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result as string);
reader.onerror = reject;
});

export const loadImage = (src: string) =>
new Promise<HTMLImageElement>((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = (e) => reject(e);
img.src = src;
});

export const getRGBAbyImageData = (imageData: ImageData, x: number, y: number, width: number) => {
return [
imageData.data[(x + y * width) * 4],
imageData.data[(x + y * width) * 4 + 1],
imageData.data[(x + y * width) * 4 + 2],
imageData.data[(x + y * width) * 4 + 3] / 255
];
}
return [
imageData.data[(x + y * width) * 4],
imageData.data[(x + y * width) * 4 + 1],
imageData.data[(x + y * width) * 4 + 2],
imageData.data[(x + y * width) * 4 + 3] / 255
];
};

// ピクセル化(サンプリング) (pixelSizeの大きさ)
export const executePixelationSampling = (context: CanvasRenderingContext2D, img: HTMLImageElement, pixelSize: number) => {
const newWidth = Math.floor(img.width / pixelSize);
const newHeight = Math.floor(img.height / pixelSize);

// draw original image
context.canvas.width = img.width;
context.canvas.height = img.height;
context.drawImage(img, 0, 0);

const imageData = context.getImageData(0, 0, img.width, img.height);
const newImageData = new ImageData(newWidth, newHeight);

for (let y = 0; y < img.height; y += pixelSize) {
for (let x = 0; x < img.width; x += pixelSize) {

const red = imageData.data[((img.width * y) + x) * 4];
const green = imageData.data[((img.width * y) + x) * 4 + 1];
const blue = imageData.data[((img.width * y) + x) * 4 + 2];
const alpha = imageData.data[((img.width * y) + x) * 4 + 3];

newImageData.data[((newWidth * (y / pixelSize)) + (x / pixelSize)) * 4] = red;
newImageData.data[((newWidth * (y / pixelSize)) + (x / pixelSize)) * 4 + 1] = green;
newImageData.data[((newWidth * (y / pixelSize)) + (x / pixelSize)) * 4 + 2] = blue;
newImageData.data[((newWidth * (y / pixelSize)) + (x / pixelSize)) * 4 + 3] = alpha;
}
}

context.canvas.width = newWidth;
context.canvas.height = newHeight;
context.putImageData(newImageData, 0, 0);

return newImageData;
}
export const executePixelationSampling = (
context: CanvasRenderingContext2D,
img: HTMLImageElement,
pixelSize: number
) => {
const newWidth = Math.floor(img.width / pixelSize);
const newHeight = Math.floor(img.height / pixelSize);

// draw original image
context.canvas.width = img.width;
context.canvas.height = img.height;
context.drawImage(img, 0, 0);

const imageData = context.getImageData(0, 0, img.width, img.height);
const newImageData = new ImageData(newWidth, newHeight);

for (let y = 0; y < img.height; y += pixelSize) {
for (let x = 0; x < img.width; x += pixelSize) {
const red = imageData.data[(img.width * y + x) * 4];
const green = imageData.data[(img.width * y + x) * 4 + 1];
const blue = imageData.data[(img.width * y + x) * 4 + 2];
const alpha = imageData.data[(img.width * y + x) * 4 + 3];

newImageData.data[(newWidth * (y / pixelSize) + x / pixelSize) * 4] = red;
newImageData.data[(newWidth * (y / pixelSize) + x / pixelSize) * 4 + 1] = green;
newImageData.data[(newWidth * (y / pixelSize) + x / pixelSize) * 4 + 2] = blue;
newImageData.data[(newWidth * (y / pixelSize) + x / pixelSize) * 4 + 3] = alpha;
}
}

context.canvas.width = newWidth;
context.canvas.height = newHeight;
context.putImageData(newImageData, 0, 0);

return newImageData;
};
Loading

0 comments on commit 35a4625

Please sign in to comment.