Рэп это речетатив, наложенный на музыку, на так называемый бит. Современные библиотеки искусственного интеллекта, после революции в синтезе речи по тексту и в глубоком обучении нейросетей, элементарно позволяют сделать автоматический генератор рэп-композиций. Мечта! Нажали на кнопочку и компьютер начинает синтезировать рэпчик, какждый куплет и каждая композиция - уникальны и не повторяют предыдущих. Если компьютер сам не синтезирует музыку, битки, то в той-же программе Discord Audio Player подключаете папку с битами, трансом или брейкбитом для паралельно звучания с речетативом, и - вуаля, компьютер становится домашним рэп-исполнителем. А с захватом системного звука и записью его в mp3 файлы можно записать несколько десятков композиций для своего телефона или - выложить их в сеть для скачивания. Ничего сложного в компьютерном синтезе рэпа, к счастью, нет, и в этой статье я расскажу, как это просто сделать, с демонстрацией исходным кодом на языке C# фирмы Microsoft. Итак, теперь немного теории.
Парой умных слов будучи сказано и на примерах показано, простой генератор речитатива основывается на принципах императивно-декларативного программирования. Декларативные определения теории записываются на процедурном языке, на C#. Синтез рэпа осуществляется снизу-вверх, со слогов до куплетов, так как синтез сверху-вниз, например, преобразованием текста в стих, сложен из-за необходимости синтаксического и морфологического разбора и не пишется за приемлемое время в несколько рабочих часов. Кроме того, нисходящий анализ очень ресурсоёмок и не позволяет синтезировать рэп в реальном времени, на лету, параkлельно с проигрыванием. Чего нет в подходе синтеза снизу-вверх!
Слово это объединение от двух до пяти морфем. Морфема это слог или общеупотребительный корень одного из языков.
Рифма к слову это замена в слове 20% морфем на случайные. Новое слово остаётся созвучным оригиналу, рифмуется с ним, но отличается от него - оно новое.
Строка это объединение от двух до пяти случайных слов.
Рифма к строке это замена всех слов на их рифмы, на рифмованные слова.
Куплет может быть одного из четырёх типов: 1, 2, 3, 4.
В куплете первого типа первая случайная строка рифмуется с третьей, а вторая случайная строк - с четвёртой.
В куплете второго типа первая случайная строка рифмуется со всторой, а третья случайная строка - с четвёртой.
В куплете третьего типа первая случайная строка рифмуется со второй, третьей и четвёртой строкой.
В куплете четвёртого типа первая случайная строка рифмуется с четвёртой, а вторая - с третьей.
Стих это объединение от двух до пяти случайных рифмованных куплетов.
Рэп-поток это непрерывное озвучивание генерируемых стихов, возможно с паралkельным звучанием музыки. Озвучивание текста осуществляется генератором речи по тексту на большой громкости и на большой скорости.
Вот и вся теория простого генератора рэп-композиций, программная реализация которой демонстрируется следующим листингом исходных кодов на языке C#. Звучание такого рэпчика чрезвычайно-захватывающе и заходит под трансовые композиции брейкбита в программе Discord Radio Player, ссылку на которую я дам в одном из следующих сообщений. Сегодня родился стиль ТрансРэп - компьютерный рэпчик, наложенный на транс или брейкбит!
Code: Select all
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Speech.Synthesis;
namespace MachineSpeechLibrary
{
public class Rap
{
protected string[] morphems = new string[]
{
"a","the","is","was","yes","no","are","you","we","he",
"she","it","as","me","iam",
"low","bis","ness","less","near",
"far","in","on","under","before","late","under","after","of","off",
"po","pi","pu","py","pe","to","ti","tu","te","ro",
"ru","ri","re","wo","wi","wu","qo",
"qi","qu","qe","pa","ta","ra","wa","qa","sa","da",
"fa","ga","ha","ja","ka","la","lo","li","lu","le",
"ly","le","ko","ki","ku","ky","ke","jo","ji","ju",
"jy","je","ho","hi","hu","hy","he","go","gi","gu",
"gy","ge","fo","fi","fu","fy","fe","do","di",
"du","dy","de","so","si","su","sy","se","sistem","zo",
"za","zi","zu","zy","ze","xo","xi","xu","xy","xe",
"xa","co","ci","cu","cy","ce","ca","vo","vi","vu",
"vy","va","bo","bi","bu","by","be","ba","no","ni",
"nu","ny","ne","na","mo","mi","my","ma","mom","child",
"guy","girl","father","mother","friend","boss",
"sex","fuck","cock","dick","pussy","love","feel","like","seem",
"exit","fail","quit","enter","login","run","press","start","stop","system","comp",
"break","case","switch","net","inet","key","man","wooman",
"all","wall","walk","go","inter","play","kiss","for","goto","mail","chat","client","soft",
"ware","hard","dream","cosmo","planet","netpun","pluton","moon","sun","earth","mars",
"volt","amper","kilo","mega","byte","bit","word","file","giga","milli","mini","nano",
"buck","money","sum","plus","minus","multi","div","per","into","later","quick","finish",
"write","code","hex","octal","dec","inc","move","push","pop","int","float","double","bool",
"string","char","list","var","able","dis","lock","asm","see","cat","call","mask","ret",
"out","space","wire","cur","rent","while","loop","each",
"one","two","free","four","five","six","seven","eight","nine","ten","zero",
"high","low","many","small","big","too"
};
Random rnd = new Random();
protected List<string> Word
{
get
{
int n = rnd.Next(2, 5);
List<string> res = new List<string>();
for (int i = 0; i < n; i++) res.Add(morphems[rnd.Next(morphems.Length)]);
return res;
}
}
protected List<List<string>> Sentence
{
get
{
int n = rnd.Next(2, 5);
List<List<string>> res = new List<List<string>>();
for (int i = 0; i < n; i++) res.Add(Word);
return res;
}
}
protected List<string> Rithma(List<string> word)
{
List<string> res = new List<string>();
foreach (string w in word)
if (rnd.Next(10) < 8) res.Add(w);
else res.Add(morphems[rnd.Next(morphems.Length)]);
return res;
}
protected List<List<string>> Rithma(List<List<string>> sent)
{
List<List<string>> res = new List<List<string>>();
foreach (List<string> w in sent) res.Add(Rithma(w));
return res;
}
protected List<List<List<string>>> Kuplet_1
{
get {
List<List<List<string>>> res = new List<List<List<string>>>();
List<List<string>> sent1 = Sentence;
List<List<string>> sent2 = Sentence;
List<List<string>> sent3 = Rithma(sent1);
List<List<string>> sent4 = Rithma(sent2);
res.Add(sent1); res.Add(sent2); res.Add(sent3); res.Add(sent4);
return res;
}
}
protected List<List<List<string>>> Kuplet_2
{
get
{
List<List<List<string>>> res = new List<List<List<string>>>();
List<List<string>> sent1 = Sentence;
List<List<string>> sent2 = Rithma(sent1);
List<List<string>> sent3 = Sentence;
List<List<string>> sent4 = Rithma(sent3);
res.Add(sent1); res.Add(sent2); res.Add(sent3); res.Add(sent4);
return res;
}
}
protected List<List<List<string>>> Kuplet_3
{
get
{
List<List<List<string>>> res = new List<List<List<string>>>();
List<List<string>> sent1 = Sentence;
List<List<string>> sent2 = Rithma(sent1);
List<List<string>> sent3 = Rithma(sent1);
List<List<string>> sent4 = Rithma(sent1);
res.Add(sent1); res.Add(sent2); res.Add(sent3); res.Add(sent4);
return res;
}
}
protected List<List<List<string>>> Kuplet_4
{
get
{
List<List<List<string>>> res = new List<List<List<string>>>();
List<List<string>> sent1 = Sentence;
List<List<string>> sent2 = Sentence;
List<List<string>> sent3 = Rithma(sent2);
List<List<string>> sent4 = Rithma(sent1);
res.Add(sent1); res.Add(sent2); res.Add(sent3); res.Add(sent4);
return res;
}
}
protected string WordText(List<string> word)
{
string res = ""; foreach (string w in word) res += w; return res;
}
protected string ToText(List<List<string>> sent)
{
string res = ""; foreach (List<string> w in sent) res += WordText(w) + " ";
return res;
}
protected string ToText(List<List<List<string>>> kuplet)
{
string res = ""; foreach (List<List<string>> s in kuplet) res += ToText(s) + ". ";// "\r\n";
return res;
}
public string Poem
{
get
{
int n = rnd.Next(3, 10);
string res = "";
for (int i = 0; i < n; i++)
{
int k = rnd.Next(4);
switch(k)
{
case 0: res += ToText(Kuplet_1); break;
case 1: res += ToText(Kuplet_2); break;
case 2: res += ToText(Kuplet_3); break;
case 3: res += ToText(Kuplet_4); break;
}
}
return res;
}
}
protected bool StopFlag = false;
public bool IsPlaying = false;
public async Task Play()
{
StopFlag = false;
IsPlaying = true;
try
{
SpeechSynthesizer syn = new SpeechSynthesizer();
syn.Rate = 4;
syn.Volume = 99;
syn.SelectVoiceByHints(VoiceGender.NotSet, VoiceAge.NotSet, 0, new System.Globalization.CultureInfo("en-US"));
while (!StopFlag)
{
syn.Speak(Poem);
}
}
catch { }
IsPlaying = false;
}
public void Stop() { StopFlag = true; }
}
}