import 'muzik_kataloglari.dart'; /// Müzik sihirbazı seçimleri → ACE-Step tags + negatif + söz iskeleti türetme. class SihirbazSecimleri { SihirbazSecimleri({ Set? sanatcilar, Set? stilReferanslari, Set? kulturler, Set? turler, Set? moodlar, Set? vokalKarakterleri, Set? vokalDetaylari, Set? miksSecenekleri, Set? enstrumanlar, this.prodKalitesi = '', this.vokalModu = 'kadin', this.bpm = 110, this.enerji = 60, this.yaraticilik = 0.85, this.ekstraNot = '', // Şarkı yapısı this.acilis = '', this.kapanis = '', this.vokalPace = '', this.enerjiEgrisi = '', this.enstrumantalAra = false, this.nakaratTekrari = 'orta', this.temizMi = false, // Negatif prompt this.negatifPrompt = '', this.otoNegatif = true, // NSFW (18+) this.nsfwAcik = false, Set? nsfwTemalar, }) : sanatcilar = sanatcilar ?? {}, stilReferanslari = stilReferanslari ?? {}, kulturler = kulturler ?? {}, turler = turler ?? {}, moodlar = moodlar ?? {}, vokalKarakterleri = vokalKarakterleri ?? {}, vokalDetaylari = vokalDetaylari ?? {}, miksSecenekleri = miksSecenekleri ?? {}, enstrumanlar = enstrumanlar ?? {}, nsfwTemalar = nsfwTemalar ?? {}; final Set sanatcilar; final Set stilReferanslari; final Set kulturler; final Set turler; final Set moodlar; final Set vokalKarakterleri; final Set vokalDetaylari; final Set miksSecenekleri; final Set enstrumanlar; final String prodKalitesi; final String vokalModu; final int bpm; final int enerji; final double yaraticilik; final String ekstraNot; // Şarkı yapısı (tek seçimler) final String acilis; // acilisSecenekleri id final String kapanis; // kapanisSecenekleri id final String vokalPace; // vokalPace id final String enerjiEgrisi; // enerjiEgrisi id final bool enstrumantalAra; final String nakaratTekrari; // 'az' | 'orta' | 'cok' final bool temizMi; // Negatif prompt final String negatifPrompt; final bool otoNegatif; // NSFW (18+) final bool nsfwAcik; final Set nsfwTemalar; bool get enstrumantalMi => vokalModu == 'enstrumantal'; /// Yaratıcılık (0-1.5) → LM temperature (0.4-1.6) double get lmTemperature => double.parse((0.4 + (yaraticilik / 1.5) * 1.2).toStringAsFixed(2)); /// Enerji (0-100) → CFG (3.0-9.5) double get cfg => double.parse((3.0 + (enerji / 100) * 6.5).toStringAsFixed(2)); static String? _promptBul(List katalog, String id) { for (final o in katalog) { if (o.id == id) return o.promptEn; } return null; } /// Seçimlerden İngilizce ACE-Step tags string'i derler. String promptDerle() { final parcalar = []; void ekleHepsi(List katalog, Set secimler) { for (final id in secimler) { final pr = _promptBul(katalog, id); if (pr != null && pr.isNotEmpty) parcalar.add(pr); } } // Sanatçı + stil referansları en başta (en güçlü stil sinyali). ekleHepsi(MuzikKataloglari.sanatcilar, sanatcilar); ekleHepsi(MuzikKataloglari.stilReferanslari, stilReferanslari); final vokal = _promptBul(MuzikKataloglari.vokalModlari, vokalModu); if (vokal != null) parcalar.add(vokal); if (!enstrumantalMi) ekleHepsi(MuzikKataloglari.kulturler, kulturler); ekleHepsi([...MuzikKataloglari.turler, ...MuzikKataloglari.konusmaTurleri], turler); ekleHepsi(MuzikKataloglari.moodlar, moodlar); if (!enstrumantalMi) { ekleHepsi([ ...MuzikKataloglari.vokalKarakterleri, ...MuzikKataloglari.konusmaVokalleri, ], vokalKarakterleri); ekleHepsi(MuzikKataloglari.vokalDetaylari, vokalDetaylari); } ekleHepsi(MuzikKataloglari.tumEnstrumanlar, enstrumanlar); // Prodüksiyon kalitesi (tek seçim) final kalite = _promptBul(MuzikKataloglari.prodKalitesi, prodKalitesi); if (kalite != null) parcalar.add(kalite); // Miks seçenekleri ekleHepsi(MuzikKataloglari.miksSecenekleri, miksSecenekleri); // Yapı / dinamik tek seçimleri (tag olarak) void ekleTek(List katalog, String id) { final pr = _promptBul(katalog, id); if (pr != null) parcalar.add(pr); } ekleTek(MuzikKataloglari.acilisSecenekleri, acilis); ekleTek(MuzikKataloglari.kapanisSecenekleri, kapanis); if (!enstrumantalMi) ekleTek(MuzikKataloglari.vokalPace, vokalPace); ekleTek(MuzikKataloglari.enerjiEgrisi, enerjiEgrisi); if (enstrumantalAra) parcalar.add('instrumental break section'); if (!enstrumantalMi && temizMi) parcalar.add('clean lyrics, radio edit'); parcalar.add(MuzikKataloglari.bpmPromptEn(bpm)); parcalar.add(MuzikKataloglari.enerjiPromptEn(enerji)); if (ekstraNot.trim().isNotEmpty) parcalar.add(ekstraNot.trim()); // NSFW temaları (yalnız 18+ açıkken) if (nsfwAcik) { for (final id in nsfwTemalar) { final p = _promptBul(MuzikKataloglari.nsfwTemalar, id); if (p != null) parcalar.add(p); } } return parcalar.join(', '); } /// Negatif prompt — temel kalite reddi + mood bazlı + kullanıcı metni. String negatifDerle() { final parcalar = []; if (otoNegatif) { parcalar.add( 'low quality, muffled, distorted, noise, clipping, autotune artifacts'); if (enstrumantalMi) parcalar.add('vocals'); // Mood bazlı zıt reddi bool moodVar(String id) => moodlar.contains(id); if (moodVar('energetic') || moodVar('aggressive') || moodVar('intense')) { parcalar.add('boring, sleepy, sluggish'); } if (moodVar('calm') || moodVar('peaceful') || moodVar('romantic')) { parcalar.add('aggressive, harsh, chaotic'); } if (moodVar('dark') || moodVar('sad') || moodVar('melancholic')) { parcalar.add('cheerful, upbeat'); } if (moodVar('uplifting') || moodVar('hopeful')) { parcalar.add('depressing, gloomy'); } } if (negatifPrompt.trim().isNotEmpty) parcalar.add(negatifPrompt.trim()); return parcalar.join(', '); } static const _introYok = {'no_intro', 'cold_vocals', 'instant_hook'}; static const _introEnstrumantal = { 'long_inst', 'drum_intro', 'bass_intro', 'piano_intro', 'guitar_intro', 'atmos_intro', 'orch_intro', 'sfx_intro', }; /// Yapı seçeneklerine göre söz iskeleti üretir. String sozTaslagi() { if (enstrumantalMi) return ''; final b = []; if (!_introYok.contains(acilis)) { if (acilis == 'acap_intro') { b.add('[intro - a cappella]'); } else if (_introEnstrumantal.contains(acilis)) { b.add('[intro - instrumental]'); } else { b.add('[intro]'); } } b..add('[verse]')..add('[chorus]')..add('[verse]')..add('[chorus]'); if (enstrumantalAra) b.add('[instrumental break]'); b.add('[bridge]'); final tekrar = switch (nakaratTekrari) { 'az' => 1, 'cok' => 3, _ => 2, }; for (var i = 0; i < tekrar; i++) { b.add('[chorus]'); } if (kapanis != 'no_outro') b.add('[outro]'); return b.join('\n\n'); } SihirbazSecimleri kopyala({ Set? sanatcilar, Set? stilReferanslari, Set? kulturler, Set? turler, Set? moodlar, Set? vokalKarakterleri, Set? vokalDetaylari, Set? miksSecenekleri, Set? enstrumanlar, String? prodKalitesi, String? vokalModu, int? bpm, int? enerji, double? yaraticilik, String? ekstraNot, String? acilis, String? kapanis, String? vokalPace, String? enerjiEgrisi, bool? enstrumantalAra, String? nakaratTekrari, bool? temizMi, String? negatifPrompt, bool? otoNegatif, bool? nsfwAcik, Set? nsfwTemalar, }) => SihirbazSecimleri( sanatcilar: sanatcilar ?? this.sanatcilar, stilReferanslari: stilReferanslari ?? this.stilReferanslari, kulturler: kulturler ?? this.kulturler, turler: turler ?? this.turler, moodlar: moodlar ?? this.moodlar, vokalKarakterleri: vokalKarakterleri ?? this.vokalKarakterleri, vokalDetaylari: vokalDetaylari ?? this.vokalDetaylari, miksSecenekleri: miksSecenekleri ?? this.miksSecenekleri, enstrumanlar: enstrumanlar ?? this.enstrumanlar, prodKalitesi: prodKalitesi ?? this.prodKalitesi, vokalModu: vokalModu ?? this.vokalModu, bpm: bpm ?? this.bpm, enerji: enerji ?? this.enerji, yaraticilik: yaraticilik ?? this.yaraticilik, ekstraNot: ekstraNot ?? this.ekstraNot, acilis: acilis ?? this.acilis, kapanis: kapanis ?? this.kapanis, vokalPace: vokalPace ?? this.vokalPace, enerjiEgrisi: enerjiEgrisi ?? this.enerjiEgrisi, enstrumantalAra: enstrumantalAra ?? this.enstrumantalAra, nakaratTekrari: nakaratTekrari ?? this.nakaratTekrari, temizMi: temizMi ?? this.temizMi, negatifPrompt: negatifPrompt ?? this.negatifPrompt, otoNegatif: otoNegatif ?? this.otoNegatif, nsfwAcik: nsfwAcik ?? this.nsfwAcik, nsfwTemalar: nsfwTemalar ?? this.nsfwTemalar, ); Map toJson() => { 'sanatcilar': sanatcilar.toList(), 'stilReferanslari': stilReferanslari.toList(), 'kulturler': kulturler.toList(), 'turler': turler.toList(), 'moodlar': moodlar.toList(), 'vokalKarakterleri': vokalKarakterleri.toList(), 'vokalDetaylari': vokalDetaylari.toList(), 'miksSecenekleri': miksSecenekleri.toList(), 'enstrumanlar': enstrumanlar.toList(), 'prodKalitesi': prodKalitesi, 'vokalModu': vokalModu, 'bpm': bpm, 'enerji': enerji, 'yaraticilik': yaraticilik, 'ekstraNot': ekstraNot, 'acilis': acilis, 'kapanis': kapanis, 'vokalPace': vokalPace, 'enerjiEgrisi': enerjiEgrisi, 'enstrumantalAra': enstrumantalAra, 'nakaratTekrari': nakaratTekrari, 'temizMi': temizMi, 'negatifPrompt': negatifPrompt, 'otoNegatif': otoNegatif, 'nsfwAcik': nsfwAcik, 'nsfwTemalar': nsfwTemalar.toList(), }; factory SihirbazSecimleri.fromJson(Map j) { Set kume(String anahtar) => Set.from((j[anahtar] as List?) ?? const []); return SihirbazSecimleri( sanatcilar: kume('sanatcilar'), stilReferanslari: kume('stilReferanslari'), kulturler: kume('kulturler'), turler: kume('turler'), moodlar: kume('moodlar'), vokalKarakterleri: kume('vokalKarakterleri'), vokalDetaylari: kume('vokalDetaylari'), miksSecenekleri: kume('miksSecenekleri'), enstrumanlar: kume('enstrumanlar'), prodKalitesi: j['prodKalitesi'] as String? ?? '', vokalModu: j['vokalModu'] as String? ?? 'kadin', bpm: j['bpm'] as int? ?? 110, enerji: j['enerji'] as int? ?? 60, yaraticilik: (j['yaraticilik'] as num?)?.toDouble() ?? 0.85, ekstraNot: j['ekstraNot'] as String? ?? '', acilis: j['acilis'] as String? ?? '', kapanis: j['kapanis'] as String? ?? '', vokalPace: j['vokalPace'] as String? ?? '', enerjiEgrisi: j['enerjiEgrisi'] as String? ?? '', enstrumantalAra: j['enstrumantalAra'] as bool? ?? false, nakaratTekrari: j['nakaratTekrari'] as String? ?? 'orta', temizMi: j['temizMi'] as bool? ?? false, negatifPrompt: j['negatifPrompt'] as String? ?? '', otoNegatif: j['otoNegatif'] as bool? ?? true, nsfwAcik: j['nsfwAcik'] as bool? ?? false, nsfwTemalar: kume('nsfwTemalar'), ); } }