Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions renzos-sound-studio/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
36 changes: 36 additions & 0 deletions renzos-sound-studio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
Binary file added renzos-sound-studio/app/favicon.ico
Binary file not shown.
26 changes: 26 additions & 0 deletions renzos-sound-studio/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@import "tailwindcss";

:root {
--background: #ffffff;
--foreground: #171717;
}

@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
}

@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}

body {
background: var(--background);
color: var(--foreground);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
}
21 changes: 21 additions & 0 deletions renzos-sound-studio/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Metadata } from "next";
import "./globals.css";

export const metadata: Metadata = {
title: "Renzo's Sound Studio - Learn Music Theory",
description: "Interactive music theory lessons with audio examples and engaging quizzes",
};

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className="antialiased">
{children}
</body>
</html>
);
}
5 changes: 5 additions & 0 deletions renzos-sound-studio/app/lessons/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import LessonPage from '@/components/pages/LessonPage';

export default function Lessons() {
return <LessonPage />;
}
5 changes: 5 additions & 0 deletions renzos-sound-studio/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import HomePage from '@/components/pages/HomePage';

export default function Home() {
return <HomePage />;
}
5 changes: 5 additions & 0 deletions renzos-sound-studio/app/practice/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import PracticePage from '@/components/pages/PracticePage';

export default function Practice() {
return <PracticePage />;
}
38 changes: 38 additions & 0 deletions renzos-sound-studio/components/audio/AudioPlayer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use client';

import { useState } from 'react';
import { Play, Pause, Volume2 } from 'lucide-react';
import { audioEngine } from '@/lib/audio/audioEngine';

interface AudioPlayerProps {
notes: string[];
label?: string;
}

export default function AudioPlayer({ notes, label }: AudioPlayerProps) {
const [isPlaying, setIsPlaying] = useState(false);

const handlePlay = async () => {
setIsPlaying(true);
await audioEngine.playSequence(notes, 0.5);
setIsPlaying(false);
};

return (
<div className="flex items-center gap-3 p-4 bg-gray-100 rounded-lg">
<button
onClick={handlePlay}
disabled={isPlaying}
className="p-2 bg-blue-500 text-white rounded-full hover:bg-blue-600 disabled:bg-gray-400 transition-colors"
aria-label={isPlaying ? 'Playing' : 'Play'}
>
{isPlaying ? <Pause size={20} /> : <Play size={20} />}
</button>
<div className="flex items-center gap-2">
<Volume2 size={20} className="text-gray-600" />
{label && <span className="text-sm font-medium">{label}</span>}
</div>
<div className="text-sm text-gray-600">{notes.join(' - ')}</div>
</div>
);
}
64 changes: 64 additions & 0 deletions renzos-sound-studio/components/lessons/ChordsLesson.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
'use client';

import AudioPlayer from '@/components/audio/AudioPlayer';

export default function ChordsLesson() {
const chords = [
{ name: 'C Major', notes: ['C4', 'E4', 'G4'] },
{ name: 'A Minor', notes: ['A3', 'C4', 'E4'] },
{ name: 'F Major', notes: ['F3', 'A3', 'C4'] },
{ name: 'G Major', notes: ['G3', 'B3', 'D4'] },
];

return (
<div className="max-w-4xl mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">Basic Chords</h1>

<div className="prose max-w-none">
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">What are Chords?</h2>
<p className="text-gray-700 mb-4">
A chord is formed when three or more notes are played simultaneously. Chords provide
the harmonic foundation for most Western music.
</p>
<p className="text-gray-700 mb-4">
The most basic type of chord is a <strong>triad</strong>, which consists of three notes:
the root, the third, and the fifth.
</p>
</section>

<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">Common Chords</h2>
<div className="space-y-4">
{chords.map((chord) => (
<div key={chord.name} className="bg-white p-4 rounded-lg shadow">
<h3 className="font-semibold mb-2">{chord.name}</h3>
<AudioPlayer notes={chord.notes} label={`Play ${chord.name}`} />
</div>
))}
</div>
</section>

<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">Major vs Minor Chords</h2>
<div className="bg-blue-50 p-6 rounded-lg">
<p className="text-gray-700 mb-4">
The difference between major and minor chords lies in the third:
</p>
<ul className="list-disc list-inside space-y-2 text-gray-700">
<li>
<strong>Major Chord</strong>: Root + Major 3rd (4 semitones) + Perfect 5th (7 semitones)
</li>
<li>
<strong>Minor Chord</strong>: Root + Minor 3rd (3 semitones) + Perfect 5th (7 semitones)
</li>
</ul>
<p className="text-gray-700 mt-4">
Major chords tend to sound bright and happy, while minor chords sound more somber and sad.
</p>
</div>
</section>
</div>
</div>
);
}
60 changes: 60 additions & 0 deletions renzos-sound-studio/components/lessons/IntervalsLesson.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use client';

import AudioPlayer from '@/components/audio/AudioPlayer';

export default function IntervalsLesson() {
const intervals = [
{ name: 'Perfect Unison', notes: ['C4', 'C4'] },
{ name: 'Major 2nd', notes: ['C4', 'D4'] },
{ name: 'Major 3rd', notes: ['C4', 'E4'] },
{ name: 'Perfect 4th', notes: ['C4', 'F4'] },
{ name: 'Perfect 5th', notes: ['C4', 'G4'] },
{ name: 'Octave', notes: ['C4', 'C5'] },
];

return (
<div className="max-w-4xl mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">Musical Intervals</h1>

<div className="prose max-w-none">
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">What are Intervals?</h2>
<p className="text-gray-700 mb-4">
An interval is the distance between two pitches. Intervals are the building blocks
of melodies, harmonies, and chords.
</p>
<p className="text-gray-700 mb-4">
Intervals are measured in semitones (half steps). Each interval has a specific sound
and character that makes it unique.
</p>
</section>

<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">Common Intervals</h2>
<div className="space-y-4">
{intervals.map((interval) => (
<div key={interval.name} className="bg-white p-4 rounded-lg shadow">
<h3 className="font-semibold mb-2">{interval.name}</h3>
<AudioPlayer notes={interval.notes} label={`Play ${interval.name}`} />
</div>
))}
</div>
</section>

<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">Interval Quality</h2>
<div className="bg-blue-50 p-6 rounded-lg">
<p className="text-gray-700 mb-4">
Intervals can be classified by their quality:
</p>
<ul className="list-disc list-inside space-y-2 text-gray-700">
<li><strong>Perfect</strong>: Unison, 4th, 5th, Octave</li>
<li><strong>Major/Minor</strong>: 2nd, 3rd, 6th, 7th</li>
<li><strong>Augmented/Diminished</strong>: Altered versions of the above</li>
</ul>
</div>
</section>
</div>
</div>
);
}
49 changes: 49 additions & 0 deletions renzos-sound-studio/components/lessons/MajorScaleLesson.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use client';

import AudioPlayer from '@/components/audio/AudioPlayer';

export default function MajorScaleLesson() {
const cMajorScale = ['C4', 'D4', 'E4', 'F4', 'G4', 'A4', 'B4', 'C5'];

return (
<div className="max-w-4xl mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">The Major Scale</h1>

<div className="prose max-w-none">
<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">What is a Major Scale?</h2>
<p className="text-gray-700 mb-4">
The major scale is one of the most fundamental concepts in Western music theory.
It consists of seven notes arranged in a specific pattern of whole steps and half steps.
</p>
<p className="text-gray-700 mb-4">
The pattern is: <strong>W-W-H-W-W-W-H</strong> (W = whole step, H = half step)
</p>
</section>

<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">C Major Scale</h2>
<p className="text-gray-700 mb-4">
Let's listen to the C major scale, which contains no sharps or flats:
</p>
<AudioPlayer notes={cMajorScale} label="C Major Scale" />
</section>

<section className="mb-8">
<h2 className="text-2xl font-semibold mb-4">Practice Exercise</h2>
<div className="bg-blue-50 p-6 rounded-lg">
<p className="text-gray-700 mb-4">
Try to identify the major scale pattern in other keys. Remember the formula:
W-W-H-W-W-W-H
</p>
<ul className="list-disc list-inside space-y-2 text-gray-700">
<li>Start on any note</li>
<li>Follow the pattern of whole and half steps</li>
<li>You should end up one octave higher on the same note</li>
</ul>
</div>
</section>
</div>
</div>
);
}
Loading