Spaces:
Sleeping
Sleeping
Update server.js
Browse files
server.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
const express = require('express');
|
| 2 |
const multer = require('multer');
|
| 3 |
const cors = require('cors');
|
|
@@ -29,95 +33,256 @@ const upload = multer({
|
|
| 29 |
limits: { fileSize: 50 * 1024 * 1024 }
|
| 30 |
});
|
| 31 |
|
| 32 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
const EFFECTS = {
|
| 34 |
lofi: {
|
| 35 |
name: "LoFi Hip Hop",
|
| 36 |
-
description: "Vintage warmth
|
| 37 |
-
|
|
|
|
|
|
|
|
|
|
| 38 |
},
|
| 39 |
|
| 40 |
slowed_reverb: {
|
| 41 |
name: "Slowed + Reverb",
|
| 42 |
-
description: "
|
| 43 |
-
|
| 44 |
-
|
|
|
|
|
|
|
| 45 |
},
|
| 46 |
|
| 47 |
nightcore: {
|
| 48 |
name: "Nightcore",
|
| 49 |
-
description: "High energy
|
| 50 |
-
|
|
|
|
|
|
|
|
|
|
| 51 |
},
|
| 52 |
|
| 53 |
vaporwave: {
|
| 54 |
name: "Vaporwave",
|
| 55 |
-
description: "Retro
|
| 56 |
-
|
|
|
|
|
|
|
|
|
|
| 57 |
},
|
| 58 |
|
| 59 |
"8d_audio": {
|
| 60 |
name: "8D Audio",
|
| 61 |
-
description: "360Β°
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
| 63 |
},
|
| 64 |
|
| 65 |
bass_boosted: {
|
| 66 |
name: "Bass Boosted",
|
| 67 |
-
description: "
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
| 69 |
},
|
| 70 |
|
| 71 |
ambient: {
|
| 72 |
name: "Ambient Chill",
|
| 73 |
-
description: "Ethereal
|
| 74 |
-
|
|
|
|
|
|
|
|
|
|
| 75 |
},
|
| 76 |
|
| 77 |
tiktok_lofi: {
|
| 78 |
name: "TikTok LoFi",
|
| 79 |
-
description: "Viral
|
| 80 |
-
|
|
|
|
|
|
|
|
|
|
| 81 |
},
|
| 82 |
|
| 83 |
chill_lofi: {
|
| 84 |
name: "Chill LoFi",
|
| 85 |
-
description: "Study
|
| 86 |
-
|
|
|
|
|
|
|
|
|
|
| 87 |
}
|
| 88 |
};
|
| 89 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
// π₯ Health Check
|
| 91 |
app.get('/', (req, res) => {
|
| 92 |
res.json({
|
| 93 |
status: 'online',
|
| 94 |
-
message: 'π΅ LoFi Remix API
|
| 95 |
-
version: '
|
| 96 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
total_effects: Object.keys(EFFECTS).length,
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
name: EFFECTS[key].name,
|
| 101 |
-
description: EFFECTS[key].description
|
| 102 |
-
})),
|
| 103 |
-
endpoints: {
|
| 104 |
-
health: 'GET /',
|
| 105 |
-
process: 'POST /process',
|
| 106 |
-
download: 'GET /download/:filename',
|
| 107 |
-
effects: 'GET /effects'
|
| 108 |
-
}
|
| 109 |
-
});
|
| 110 |
-
});
|
| 111 |
-
|
| 112 |
-
// ποΈ Get Available Effects
|
| 113 |
-
app.get('/effects', (req, res) => {
|
| 114 |
-
res.json({
|
| 115 |
-
total: Object.keys(EFFECTS).length,
|
| 116 |
-
effects: Object.keys(EFFECTS).map(key => ({
|
| 117 |
-
id: key,
|
| 118 |
-
name: EFFECTS[key].name,
|
| 119 |
-
description: EFFECTS[key].description
|
| 120 |
-
}))
|
| 121 |
});
|
| 122 |
});
|
| 123 |
|
|
@@ -132,6 +297,7 @@ app.post('/process', upload.single('audio'), async (req, res) => {
|
|
| 132 |
}
|
| 133 |
|
| 134 |
const effectType = req.body.effect || 'lofi';
|
|
|
|
| 135 |
|
| 136 |
if (!EFFECTS[effectType]) {
|
| 137 |
fs.unlinkSync(req.file.path);
|
|
@@ -146,13 +312,48 @@ app.post('/process', upload.single('audio'), async (req, res) => {
|
|
| 146 |
const outputFilename = `${effectType}-${Date.now()}.mp3`;
|
| 147 |
const outputPath = path.join(outputsDir, outputFilename);
|
| 148 |
|
| 149 |
-
|
| 150 |
-
console.log(`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
|
| 152 |
-
|
| 153 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
|
| 155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
|
| 157 |
const startTime = Date.now();
|
| 158 |
await execPromise(ffmpegCommand, {
|
|
@@ -165,18 +366,20 @@ app.post('/process', upload.single('audio'), async (req, res) => {
|
|
| 165 |
const stats = fs.statSync(outputPath);
|
| 166 |
const fileSizeKB = (stats.size / 1024).toFixed(2);
|
| 167 |
|
| 168 |
-
console.log(`β
|
| 169 |
|
| 170 |
res.json({
|
| 171 |
success: true,
|
| 172 |
-
message: `Processed with ${
|
| 173 |
downloadUrl: `/download/${outputFilename}`,
|
| 174 |
filename: outputFilename,
|
| 175 |
effect: {
|
| 176 |
id: effectType,
|
| 177 |
-
name:
|
| 178 |
-
description:
|
|
|
|
| 179 |
},
|
|
|
|
| 180 |
output: {
|
| 181 |
size_kb: fileSizeKB
|
| 182 |
},
|
|
@@ -210,7 +413,7 @@ app.get('/download/:filename', (req, res) => {
|
|
| 210 |
});
|
| 211 |
}
|
| 212 |
|
| 213 |
-
console.log(`π₯
|
| 214 |
|
| 215 |
res.download(filePath, filename, (err) => {
|
| 216 |
if (!err) {
|
|
@@ -224,13 +427,54 @@ app.get('/download/:filename', (req, res) => {
|
|
| 224 |
});
|
| 225 |
});
|
| 226 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 227 |
// π Start Server
|
| 228 |
app.listen(PORT, '0.0.0.0', () => {
|
| 229 |
console.log('βββββββββββββββββββββββββββββββββββββββββββββββ');
|
| 230 |
-
console.log('π LoFi Remix API
|
| 231 |
console.log('βββββββββββββββββββββββββββββββββββββββββββββββ');
|
| 232 |
console.log(`π Server: http://0.0.0.0:${PORT}`);
|
| 233 |
-
console.log(`β‘
|
| 234 |
-
console.log(`
|
|
|
|
|
|
|
| 235 |
console.log('βββββββββββββββββββββββββββββββββββββββββββββββ');
|
| 236 |
});
|
|
|
|
| 1 |
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 2 |
+
// FILE: server.js - Complete Backend with Smart Instruments
|
| 3 |
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 4 |
+
|
| 5 |
const express = require('express');
|
| 6 |
const multer = require('multer');
|
| 7 |
const cors = require('cors');
|
|
|
|
| 33 |
limits: { fileSize: 50 * 1024 * 1024 }
|
| 34 |
});
|
| 35 |
|
| 36 |
+
// πΉ βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 37 |
+
// INSTRUMENT LIBRARY - Categorized by Mood
|
| 38 |
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 39 |
+
|
| 40 |
+
const INSTRUMENTS = {
|
| 41 |
+
// π SAD INSTRUMENTS
|
| 42 |
+
sad_piano: {
|
| 43 |
+
name: "Sad Piano",
|
| 44 |
+
mood: "sad",
|
| 45 |
+
command: "aevalsrc='0.13*sin(2*PI*(220+5*sin(0.08*t))*t)*exp(-0.15*mod(t,4))':d=12,aecho=0.7:0.85:600:0.35,lowpass=f=3000"
|
| 46 |
+
},
|
| 47 |
+
melancholic_violin: {
|
| 48 |
+
name: "Melancholic Violin",
|
| 49 |
+
mood: "sad",
|
| 50 |
+
command: "aevalsrc='0.12*sin(2*PI*330*t)*sin(2*PI*0.3*t)*exp(-0.1*mod(t,5))':d=12,vibrato=f=0.15:d=0.5,aecho=0.6:0.8:500:0.3"
|
| 51 |
+
},
|
| 52 |
+
lonely_cello: {
|
| 53 |
+
name: "Lonely Cello",
|
| 54 |
+
mood: "sad",
|
| 55 |
+
command: "aevalsrc='0.14*sin(2*PI*165*t)*sin(2*PI*0.2*t)':d=12,chorus=0.4:0.7:40:0.3:0.2:2,lowpass=f=2500"
|
| 56 |
+
},
|
| 57 |
+
tearful_flute: {
|
| 58 |
+
name: "Tearful Flute",
|
| 59 |
+
mood: "sad",
|
| 60 |
+
command: "aevalsrc='0.11*sin(2*PI*440*t)*sin(2*PI*1.5*t)*exp(-0.2*mod(t,3))':d=12,aecho=0.5:0.75:400:0.3,vibrato=f=0.2:d=0.4"
|
| 61 |
+
},
|
| 62 |
+
|
| 63 |
+
// β€οΈ ROMANTIC INSTRUMENTS
|
| 64 |
+
romantic_piano: {
|
| 65 |
+
name: "Romantic Piano",
|
| 66 |
+
mood: "romantic",
|
| 67 |
+
command: "aevalsrc='0.12*(sin(2*PI*330*t)+sin(2*PI*415*t))*exp(-0.12*mod(t,3.5))':d=12,aecho=0.6:0.8:450:0.35,chorus=0.3:0.6:35:0.25:0.15:2"
|
| 68 |
+
},
|
| 69 |
+
love_strings: {
|
| 70 |
+
name: "Love Strings",
|
| 71 |
+
mood: "romantic",
|
| 72 |
+
command: "aevalsrc='0.13*(sin(2*PI*440*t)+sin(2*PI*554*t))*sin(2*PI*0.4*t)':d=12,vibrato=f=0.18:d=0.45,aecho=0.5:0.7:350:0.3"
|
| 73 |
+
},
|
| 74 |
+
gentle_harp: {
|
| 75 |
+
name: "Gentle Harp",
|
| 76 |
+
mood: "romantic",
|
| 77 |
+
command: "aevalsrc='0.11*sin(2*PI*(660+8*sin(0.15*t))*t)*exp(-0.25*mod(t,2.5))':d=12,chorus=0.4:0.7:45:0.3:0.2:2,aecho=0.6:0.8:300:0.35"
|
| 78 |
+
},
|
| 79 |
+
sweet_bells: {
|
| 80 |
+
name: "Sweet Bells",
|
| 81 |
+
mood: "romantic",
|
| 82 |
+
command: "aevalsrc='0.09*sin(2*PI*880*t)*exp(-0.4*mod(t,2))':d=12,aecho=0.5:0.75:250:0.4,vibrato=f=0.12:d=0.3"
|
| 83 |
+
},
|
| 84 |
+
|
| 85 |
+
// πβ€οΈ SAD ROMANTIC MIX
|
| 86 |
+
bittersweet_piano: {
|
| 87 |
+
name: "Bittersweet Piano",
|
| 88 |
+
mood: "sad_romantic",
|
| 89 |
+
command: "aevalsrc='0.13*(sin(2*PI*247*t)+sin(2*PI*330*t))*exp(-0.15*mod(t,4))*(1+0.3*sin(0.5*t))':d=12,aecho=0.7:0.85:500:0.35,vibrato=f=0.1:d=0.4"
|
| 90 |
+
},
|
| 91 |
+
nostalgic_violin: {
|
| 92 |
+
name: "Nostalgic Violin",
|
| 93 |
+
mood: "sad_romantic",
|
| 94 |
+
command: "aevalsrc='0.12*sin(2*PI*370*t)*sin(2*PI*0.35*t)*(1+0.2*sin(0.3*t))':d=12,chorus=0.5:0.75:40:0.3:0.2:2,aecho=0.6:0.8:450:0.3"
|
| 95 |
+
},
|
| 96 |
+
heartbreak_strings: {
|
| 97 |
+
name: "Heartbreak Strings",
|
| 98 |
+
mood: "sad_romantic",
|
| 99 |
+
command: "aevalsrc='0.13*(sin(2*PI*220*t)+sin(2*PI*330*t))*exp(-0.1*mod(t,5))':d=12,vibrato=f=0.15:d=0.5,lowpass=f=3500"
|
| 100 |
+
},
|
| 101 |
+
|
| 102 |
+
// π AMBIENT/DREAMY INSTRUMENTS
|
| 103 |
+
dreamy_pad: {
|
| 104 |
+
name: "Dreamy Pad",
|
| 105 |
+
mood: "ambient",
|
| 106 |
+
command: "aevalsrc='0.11*(sin(2*PI*165*t)+sin(2*PI*220*t)+sin(2*PI*330*t))':d=12,aphaser=in_gain=0.4:out_gain=0.7:delay=3:decay=0.4:speed=0.25,aecho=0.5:0.7:400:0.3"
|
| 107 |
+
},
|
| 108 |
+
ethereal_synth: {
|
| 109 |
+
name: "Ethereal Synth",
|
| 110 |
+
mood: "ambient",
|
| 111 |
+
command: "aevalsrc='0.1*(sin(2*PI*220*t)+sin(2*PI*277*t))*sin(2*PI*0.5*t)':d=12,chorus=0.6:0.85:50:0.4:0.25:2,aecho=0.6:0.8:500:0.3"
|
| 112 |
+
},
|
| 113 |
+
celestial_bells: {
|
| 114 |
+
name: "Celestial Bells",
|
| 115 |
+
mood: "ambient",
|
| 116 |
+
command: "aevalsrc='0.09*(sin(2*PI*880*t)+sin(2*PI*1108*t))*exp(-0.3*t)':d=12,aecho=0.7:0.9:600:0.4,aphaser=in_gain=0.3:out_gain=0.6:delay=2:decay=0.3:speed=0.2"
|
| 117 |
+
},
|
| 118 |
+
|
| 119 |
+
// πΈ CHILL/LOFI INSTRUMENTS
|
| 120 |
+
lofi_guitar: {
|
| 121 |
+
name: "LoFi Guitar",
|
| 122 |
+
mood: "chill",
|
| 123 |
+
command: "aevalsrc='0.12*sin(2*PI*196*t)*exp(-0.3*mod(t,3))*(1+0.15*random(0))':d=12,chorus=0.5:0.7:40:0.25:0.15:2,lowpass=f=4000"
|
| 124 |
+
},
|
| 125 |
+
jazzy_piano: {
|
| 126 |
+
name: "Jazzy Piano",
|
| 127 |
+
mood: "chill",
|
| 128 |
+
command: "aevalsrc='0.11*(sin(2*PI*262*t)+sin(2*PI*330*t))*exp(-0.2*mod(t,2.5))':d=12,vibrato=f=0.18:d=0.4,aecho=0.4:0.6:300:0.25"
|
| 129 |
+
},
|
| 130 |
+
smooth_sax: {
|
| 131 |
+
name: "Smooth Saxophone",
|
| 132 |
+
mood: "chill",
|
| 133 |
+
command: "aevalsrc='0.12*sin(2*PI*294*t)*sin(2*PI*2*t)':d=12,vibrato=f=0.25:d=0.5,chorus=0.4:0.7:45:0.3:0.2:2"
|
| 134 |
+
},
|
| 135 |
+
|
| 136 |
+
// β‘ UPBEAT/ENERGETIC INSTRUMENTS
|
| 137 |
+
bright_synth: {
|
| 138 |
+
name: "Bright Synth",
|
| 139 |
+
mood: "upbeat",
|
| 140 |
+
command: "aevalsrc='0.11*(sin(2*PI*440*t)+sin(2*PI*554*t)+sin(2*PI*659*t))':d=12,chorus=0.6:0.8:50:0.35:0.25:2,highpass=f=200"
|
| 141 |
+
},
|
| 142 |
+
sparkle_bells: {
|
| 143 |
+
name: "Sparkle Bells",
|
| 144 |
+
mood: "upbeat",
|
| 145 |
+
command: "aevalsrc='0.1*(sin(2*PI*1320*t)+sin(2*PI*1760*t))*exp(-0.5*mod(t,1.5))':d=12,aecho=0.4:0.6:150:0.3,highpass=f=500"
|
| 146 |
+
},
|
| 147 |
+
happy_piano: {
|
| 148 |
+
name: "Happy Piano",
|
| 149 |
+
mood: "upbeat",
|
| 150 |
+
command: "aevalsrc='0.11*(sin(2*PI*523*t)+sin(2*PI*659*t))*exp(-0.25*mod(t,2))':d=12,chorus=0.5:0.7:40:0.3:0.2:2"
|
| 151 |
+
}
|
| 152 |
+
};
|
| 153 |
+
|
| 154 |
+
// π― βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 155 |
+
// SMART EFFECT CONFIGURATIONS - Each effect has mood-matched instruments
|
| 156 |
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 157 |
+
|
| 158 |
const EFFECTS = {
|
| 159 |
lofi: {
|
| 160 |
name: "LoFi Hip Hop",
|
| 161 |
+
description: "Vintage warmth with jazzy chill vibes",
|
| 162 |
+
baseCommand: `-af "asetrate=44100*0.90,aresample=44100,bass=g=5:f=85:width_type=h:width=100,treble=g=-3:f=8000,equalizer=f=200:t=q:width=1.5:g=-2,equalizer=f=1000:t=q:width=2:g=2,acompressor=threshold=-20dB:ratio=3:attack=10:release=120:makeup=3,vibrato=f=0.2:d=0.4,highpass=f=70,lowpass=f=4500,volume=1.3"`,
|
| 163 |
+
instrumentVolume: 0.14,
|
| 164 |
+
// LoFi uses chill + some sad romantic vibes
|
| 165 |
+
instrumentMoods: ["chill", "sad_romantic", "ambient"]
|
| 166 |
},
|
| 167 |
|
| 168 |
slowed_reverb: {
|
| 169 |
name: "Slowed + Reverb",
|
| 170 |
+
description: "Dreamy slow with sad romantic atmosphere",
|
| 171 |
+
baseCommand: `-af "atempo=0.90,asetrate=44100*0.95,aresample=44100,bass=g=4:f=80:width_type=h:width=120,aecho=0.8:0.88:250:0.5,aecho=0.7:0.78:400:0.4,aecho=0.6:0.68:600:0.3,equalizer=f=100:t=q:width=2:g=3.5,equalizer=f=4000:t=q:width=4:g=-4,acompressor=threshold=-20dB:ratio=2:attack=15:release=200:makeup=2,highpass=f=50,lowpass=f=7000,volume=1.4"`,
|
| 172 |
+
instrumentVolume: 0.13,
|
| 173 |
+
// Slowed+Reverb is emotional - sad, romantic, sad_romantic mix
|
| 174 |
+
instrumentMoods: ["sad", "romantic", "sad_romantic", "ambient"]
|
| 175 |
},
|
| 176 |
|
| 177 |
nightcore: {
|
| 178 |
name: "Nightcore",
|
| 179 |
+
description: "High energy with bright sparkling sounds",
|
| 180 |
+
baseCommand: `-af "atempo=1.30,asetrate=44100*1.18,aresample=44100,treble=g=6:f=5000:width_type=h:width=3000,bass=g=-3:f=100,equalizer=f=2000:t=q:width=2:g=2.5,equalizer=f=6000:t=q:width=3:g=4,equalizer=f=10000:t=q:width=4:g=5,acompressor=threshold=-18dB:ratio=3:attack=3:release=30:makeup=4,highpass=f=120,volume=1.4"`,
|
| 181 |
+
instrumentVolume: 0.11,
|
| 182 |
+
// Nightcore is upbeat and energetic
|
| 183 |
+
instrumentMoods: ["upbeat", "romantic"]
|
| 184 |
},
|
| 185 |
|
| 186 |
vaporwave: {
|
| 187 |
name: "Vaporwave",
|
| 188 |
+
description: "Retro nostalgic with dreamy sad vibes",
|
| 189 |
+
baseCommand: `-af "asetrate=44100*0.82,aresample=44100,equalizer=f=300:t=q:width=2:g=4,equalizer=f=1500:t=q:width=3:g=-2,equalizer=f=6000:t=q:width=4:g=-4,aphaser=in_gain=0.5:out_gain=0.75:delay=4:decay=0.5:speed=0.2,chorus=0.6:0.85:55:0.4:0.25:2,vibrato=f=0.12:d=0.5,aecho=0.5:0.65:180:0.35,acompressor=threshold=-20dB:ratio=2.5:attack=12:release=150:makeup=2,highpass=f=70,lowpass=f=5500,volume=1.2"`,
|
| 190 |
+
instrumentVolume: 0.13,
|
| 191 |
+
// Vaporwave is nostalgic - sad_romantic + ambient
|
| 192 |
+
instrumentMoods: ["sad_romantic", "ambient", "sad"]
|
| 193 |
},
|
| 194 |
|
| 195 |
"8d_audio": {
|
| 196 |
name: "8D Audio",
|
| 197 |
+
description: "Immersive 360Β° with ambient dreamy layers",
|
| 198 |
+
baseCommand: `-af "apulsator=hz=0.08:mode=sine:width=0.9,extrastereo=m=3:c=1,aecho=0.7:0.85:100:0.35,haas=level_in=1:level_out=1.1:side_gain=0.9:middle_source=mid,bass=g=3:f=85,acompressor=threshold=-18dB:ratio=2:attack=10:release=100:makeup=2,highpass=f=60,volume=1.2"`,
|
| 199 |
+
instrumentVolume: 0.12,
|
| 200 |
+
// 8D is immersive - ambient + romantic
|
| 201 |
+
instrumentMoods: ["ambient", "romantic", "sad_romantic"]
|
| 202 |
},
|
| 203 |
|
| 204 |
bass_boosted: {
|
| 205 |
name: "Bass Boosted",
|
| 206 |
+
description: "Heavy bass with deep atmospheric tones",
|
| 207 |
+
baseCommand: `-af "bass=g=18:f=55:width_type=o:width=1.5,bass=g=14:f=95:width_type=h:width=90,equalizer=f=35:t=q:width=1.2:g=12,equalizer=f=75:t=q:width=1.5:g=10,equalizer=f=140:t=q:width=2:g=8,equalizer=f=500:t=q:width=2:g=-3,equalizer=f=4000:t=q:width=4:g=-6,volume='mod(t,31):if(lt(MOD,15),0.4,if(lt(MOD,18),0.05,if(lt(MOD,26),0.5+0.0625*(MOD-18),1.5)))':eval=frame,acompressor=threshold=-22dB:ratio=8:attack=3:release=40:makeup=8,tremolo=f=0.15:d=0.3,highpass=f=28,alimiter=limit=0.95:attack=5:release=50"`,
|
| 208 |
+
instrumentVolume: 0.09,
|
| 209 |
+
// Bass boosted - deep ambient + chill
|
| 210 |
+
instrumentMoods: ["ambient", "chill"]
|
| 211 |
},
|
| 212 |
|
| 213 |
ambient: {
|
| 214 |
name: "Ambient Chill",
|
| 215 |
+
description: "Ethereal meditation with sad peaceful vibes",
|
| 216 |
+
baseCommand: `-af "asetrate=44100*0.94,aresample=44100,aecho=0.6:0.8:200:0.4,aecho=0.5:0.7:400:0.3,chorus=0.6:0.85:50:0.4:0.25:2,aphaser=in_gain=0.5:out_gain=0.8:delay=3:decay=0.4:speed=0.2,equalizer=f=1500:t=q:width=3:g=-2,equalizer=f=6000:t=q:width=4:g=-4,acompressor=threshold=-18dB:ratio=2:attack=15:release=200:makeup=3,highpass=f=50,lowpass=f=9000,volume=1.5"`,
|
| 217 |
+
instrumentVolume: 0.15,
|
| 218 |
+
// Ambient - all ambient + sad moods
|
| 219 |
+
instrumentMoods: ["ambient", "sad", "sad_romantic"]
|
| 220 |
},
|
| 221 |
|
| 222 |
tiktok_lofi: {
|
| 223 |
name: "TikTok LoFi",
|
| 224 |
+
description: "Viral style with modern romantic chill",
|
| 225 |
+
baseCommand: `-af "asetrate=44100*0.88,aresample=44100,bass=g=6:f=90:width_type=h:width=100,treble=g=-4:f=7500,equalizer=f=200:t=q:width=1.8:g=-1.5,equalizer=f=800:t=q:width=2:g=2,equalizer=f=3000:t=q:width=3:g=-2,acompressor=threshold=-20dB:ratio=4:attack=5:release=100:makeup=4,vibrato=f=0.2:d=0.5,chorus=0.5:0.8:45:0.3:0.2:2,highpass=f=70,lowpass=f=5000,volume=1.35"`,
|
| 226 |
+
instrumentVolume: 0.13,
|
| 227 |
+
// TikTok LoFi - chill + romantic
|
| 228 |
+
instrumentMoods: ["chill", "romantic", "sad_romantic"]
|
| 229 |
},
|
| 230 |
|
| 231 |
chill_lofi: {
|
| 232 |
name: "Chill LoFi",
|
| 233 |
+
description: "Study vibes with jazzy peaceful atmosphere",
|
| 234 |
+
baseCommand: `-af "asetrate=44100*0.92,aresample=44100,bass=g=5:f=88:width_type=h:width=90,treble=g=-4:f=7000,equalizer=f=250:t=q:width=2:g=-1.5,equalizer=f=1000:t=q:width=2.5:g=1.2,equalizer=f=3500:t=q:width=3:g=-2.5,acompressor=threshold=-21dB:ratio=3:attack=10:release=140:makeup=2.5,vibrato=f=0.15:d=0.45,chorus=0.4:0.8:45:0.28:0.18:2,aecho=0.4:0.6:150:0.25,highpass=f=70,lowpass=f=5000,volume=1.2"`,
|
| 235 |
+
instrumentVolume: 0.12,
|
| 236 |
+
// Chill LoFi - pure chill + ambient
|
| 237 |
+
instrumentMoods: ["chill", "ambient"]
|
| 238 |
}
|
| 239 |
};
|
| 240 |
|
| 241 |
+
// π² Smart Random Instrument Selector
|
| 242 |
+
function getSmartInstruments(effectType, count = 2) {
|
| 243 |
+
const effect = EFFECTS[effectType];
|
| 244 |
+
if (!effect || !effect.instrumentMoods) {
|
| 245 |
+
return getRandomInstruments(count);
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
// Get instruments that match the effect's moods
|
| 249 |
+
const matchingInstruments = Object.keys(INSTRUMENTS).filter(key =>
|
| 250 |
+
effect.instrumentMoods.includes(INSTRUMENTS[key].mood)
|
| 251 |
+
);
|
| 252 |
+
|
| 253 |
+
// Shuffle and select
|
| 254 |
+
const shuffled = matchingInstruments.sort(() => Math.random() - 0.5);
|
| 255 |
+
const selected = [];
|
| 256 |
+
|
| 257 |
+
for (let i = 0; i < Math.min(count, shuffled.length); i++) {
|
| 258 |
+
selected.push(shuffled[i]);
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
return selected;
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
// Fallback random selector
|
| 265 |
+
function getRandomInstruments(count = 2) {
|
| 266 |
+
const instrumentKeys = Object.keys(INSTRUMENTS);
|
| 267 |
+
const shuffled = instrumentKeys.sort(() => Math.random() - 0.5);
|
| 268 |
+
return shuffled.slice(0, count);
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
// π₯ Health Check
|
| 272 |
app.get('/', (req, res) => {
|
| 273 |
res.json({
|
| 274 |
status: 'online',
|
| 275 |
+
message: 'π΅ LoFi Remix API v3.1 - Smart Mood-Based Instruments',
|
| 276 |
+
version: '3.1',
|
| 277 |
+
features: [
|
| 278 |
+
'9 unique effects',
|
| 279 |
+
'Smart mood-based instrument selection',
|
| 280 |
+
'20+ instruments across 5 moods',
|
| 281 |
+
'Sad, Romantic, Sad-Romantic, Ambient, Chill, Upbeat'
|
| 282 |
+
],
|
| 283 |
total_effects: Object.keys(EFFECTS).length,
|
| 284 |
+
total_instruments: Object.keys(INSTRUMENTS).length,
|
| 285 |
+
instrument_moods: ['sad', 'romantic', 'sad_romantic', 'ambient', 'chill', 'upbeat']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
});
|
| 287 |
});
|
| 288 |
|
|
|
|
| 297 |
}
|
| 298 |
|
| 299 |
const effectType = req.body.effect || 'lofi';
|
| 300 |
+
const addInstruments = req.body.instruments !== 'false';
|
| 301 |
|
| 302 |
if (!EFFECTS[effectType]) {
|
| 303 |
fs.unlinkSync(req.file.path);
|
|
|
|
| 312 |
const outputFilename = `${effectType}-${Date.now()}.mp3`;
|
| 313 |
const outputPath = path.join(outputsDir, outputFilename);
|
| 314 |
|
| 315 |
+
const effect = EFFECTS[effectType];
|
| 316 |
+
console.log(`π΅ Processing: ${effect.name}`);
|
| 317 |
+
console.log(`π ${effect.description}`);
|
| 318 |
+
console.log(`π Moods: ${effect.instrumentMoods?.join(', ') || 'default'}`);
|
| 319 |
+
|
| 320 |
+
let ffmpegCommand;
|
| 321 |
+
let usedInstruments = [];
|
| 322 |
|
| 323 |
+
if (addInstruments) {
|
| 324 |
+
// π² Smart selection - 2 instruments matching effect mood
|
| 325 |
+
const selectedKeys = getSmartInstruments(effectType, 2);
|
| 326 |
+
usedInstruments = selectedKeys.map(key => ({
|
| 327 |
+
id: key,
|
| 328 |
+
name: INSTRUMENTS[key].name,
|
| 329 |
+
mood: INSTRUMENTS[key].mood
|
| 330 |
+
}));
|
| 331 |
|
| 332 |
+
console.log(`πΉ Instruments: ${usedInstruments.map(i => `${i.name} (${i.mood})`).join(', ')}`);
|
| 333 |
+
|
| 334 |
+
// Generate instruments
|
| 335 |
+
const inst1Path = path.join(outputsDir, `inst1-${Date.now()}.wav`);
|
| 336 |
+
const inst2Path = path.join(outputsDir, `inst2-${Date.now()}.wav`);
|
| 337 |
+
|
| 338 |
+
await execPromise(`ffmpeg -f lavfi -i "${INSTRUMENTS[selectedKeys[0]].command}" -t 12 -y "${inst1Path}"`);
|
| 339 |
+
await execPromise(`ffmpeg -f lavfi -i "${INSTRUMENTS[selectedKeys[1]].command}" -t 12 -y "${inst2Path}"`);
|
| 340 |
+
|
| 341 |
+
// Mix with smart volume
|
| 342 |
+
const vol = effect.instrumentVolume;
|
| 343 |
+
ffmpegCommand = `ffmpeg -i "${inputPath}" -stream_loop -1 -i "${inst1Path}" -stream_loop -1 -i "${inst2Path}" -filter_complex "[1]volume=${vol}[i1];[2]volume=${vol}[i2];[0][i1][i2]amix=inputs=3:duration=first:dropout_transition=2,${effect.baseCommand.replace('-af "', '').replace('"', '')}" -ar 44100 -b:a 192k -y "${outputPath}"`;
|
| 344 |
+
|
| 345 |
+
// Cleanup
|
| 346 |
+
setTimeout(() => {
|
| 347 |
+
[inst1Path, inst2Path].forEach(p => {
|
| 348 |
+
if (fs.existsSync(p)) fs.unlinkSync(p);
|
| 349 |
+
});
|
| 350 |
+
}, 5000);
|
| 351 |
+
|
| 352 |
+
} else {
|
| 353 |
+
ffmpegCommand = `ffmpeg -i "${inputPath}" -threads 0 ${effect.baseCommand} -ar 44100 -b:a 192k -y "${outputPath}"`;
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
console.log(`βοΈ Processing...`);
|
| 357 |
|
| 358 |
const startTime = Date.now();
|
| 359 |
await execPromise(ffmpegCommand, {
|
|
|
|
| 366 |
const stats = fs.statSync(outputPath);
|
| 367 |
const fileSizeKB = (stats.size / 1024).toFixed(2);
|
| 368 |
|
| 369 |
+
console.log(`β
Done: ${fileSizeKB}KB in ${processingTime}s`);
|
| 370 |
|
| 371 |
res.json({
|
| 372 |
success: true,
|
| 373 |
+
message: `Processed with ${effect.name}`,
|
| 374 |
downloadUrl: `/download/${outputFilename}`,
|
| 375 |
filename: outputFilename,
|
| 376 |
effect: {
|
| 377 |
id: effectType,
|
| 378 |
+
name: effect.name,
|
| 379 |
+
description: effect.description,
|
| 380 |
+
moods: effect.instrumentMoods || []
|
| 381 |
},
|
| 382 |
+
instruments: addInstruments ? usedInstruments : [],
|
| 383 |
output: {
|
| 384 |
size_kb: fileSizeKB
|
| 385 |
},
|
|
|
|
| 413 |
});
|
| 414 |
}
|
| 415 |
|
| 416 |
+
console.log(`π₯ Download: ${filename}`);
|
| 417 |
|
| 418 |
res.download(filePath, filename, (err) => {
|
| 419 |
if (!err) {
|
|
|
|
| 427 |
});
|
| 428 |
});
|
| 429 |
|
| 430 |
+
// ποΈ Get Effects Info
|
| 431 |
+
app.get('/effects', (req, res) => {
|
| 432 |
+
res.json({
|
| 433 |
+
total: Object.keys(EFFECTS).length,
|
| 434 |
+
effects: Object.keys(EFFECTS).map(key => ({
|
| 435 |
+
id: key,
|
| 436 |
+
name: EFFECTS[key].name,
|
| 437 |
+
description: EFFECTS[key].description,
|
| 438 |
+
moods: EFFECTS[key].instrumentMoods || []
|
| 439 |
+
}))
|
| 440 |
+
});
|
| 441 |
+
});
|
| 442 |
+
|
| 443 |
+
// πΉ Get Instruments Info
|
| 444 |
+
app.get('/instruments', (req, res) => {
|
| 445 |
+
const byMood = {};
|
| 446 |
+
|
| 447 |
+
Object.keys(INSTRUMENTS).forEach(key => {
|
| 448 |
+
const inst = INSTRUMENTS[key];
|
| 449 |
+
if (!byMood[inst.mood]) {
|
| 450 |
+
byMood[inst.mood] = [];
|
| 451 |
+
}
|
| 452 |
+
byMood[inst.mood].push({
|
| 453 |
+
id: key,
|
| 454 |
+
name: inst.name
|
| 455 |
+
});
|
| 456 |
+
});
|
| 457 |
+
|
| 458 |
+
res.json({
|
| 459 |
+
total: Object.keys(INSTRUMENTS).length,
|
| 460 |
+
by_mood: byMood,
|
| 461 |
+
all: Object.keys(INSTRUMENTS).map(key => ({
|
| 462 |
+
id: key,
|
| 463 |
+
name: INSTRUMENTS[key].name,
|
| 464 |
+
mood: INSTRUMENTS[key].mood
|
| 465 |
+
}))
|
| 466 |
+
});
|
| 467 |
+
});
|
| 468 |
+
|
| 469 |
// π Start Server
|
| 470 |
app.listen(PORT, '0.0.0.0', () => {
|
| 471 |
console.log('βββββββββββββββββββββββββββββββββββββββββββββββ');
|
| 472 |
+
console.log('π LoFi Remix API v3.1 - SMART INSTRUMENTS');
|
| 473 |
console.log('βββββββββββββββββββββββββββββββββββββββββββββββ');
|
| 474 |
console.log(`π Server: http://0.0.0.0:${PORT}`);
|
| 475 |
+
console.log(`β‘ Effects: ${Object.keys(EFFECTS).length}`);
|
| 476 |
+
console.log(`πΉ Instruments: ${Object.keys(INSTRUMENTS).length}`);
|
| 477 |
+
console.log(`π Moods: Sad, Romantic, Sad-Romantic, Ambient, Chill, Upbeat`);
|
| 478 |
+
console.log(`π² Smart mood-based selection!`);
|
| 479 |
console.log('βββββββββββββββββββββββββββββββββββββββββββββββ');
|
| 480 |
});
|