If your goal is purely symbolic melody generation (e.g., generating MIDI files or notes rather than full audio files) using a specific collection of folk songs, the standard workflow is to fine-tune or train an LSTM or a Music Transformer.
Below is a complete, lightweight PyTorch Melody Generator structure using a Recurrent Neural Network (LSTM).
Step A: Prepare Your Dataset
You will first need to find folk songs MIDI/ABC files (such as those from folk archives) and map the pitches into integer tokens.
import torch.nn as nn
import torch.optim as optim
import numpy as np
# Sample Hyperparameters
VOCAB_SIZE = 128 # Mapping MIDI pitches (0-127)
EMBEDDING_DIM = 64
HIDDEN_DIM = 256
SEQ_LENGTH = 20
Step B: Define the PyTorch Melody Model
python
class MelodyLSTM(nn.Module):
def __init__(self, vocab_size, embedding_dim, hidden_dim):
super(MelodyLSTM, self).__init__()
self.embedding = nn.Embedding(vocab_size, embedding_dim)
self.lstm = nn.ModuleList([
nn.LSTM(embedding_dim, hidden_dim, batch_first=True),
nn.LSTM(hidden_dim, hidden_dim, batch_first=True)
])
self.fc = nn.Linear(hidden_dim, vocab_size)
def forward(self, x, hidden=None):
# x shape: [Batch_Size, Seq_Length]
embedded = self.embedding(x)
if hidden is None:
hidden = [None] * len(self.lstm)
out = embedded
new_hidden = []
for i, lstm_layer in enumerate(self.lstm):
out, h = lstm_layer(out, hidden[i])
new_hidden.append(h)
# We only care about the last note outputted for autoregressive generation
logits = self.fc(out[:, -1, :])
return logits, new_hidden
Step C: Autoregressive Melody Inference Script
Once trained on a dataset of folk song melodies, you can seed the model with a core hook or starter note sequence to generate a new melody:
def generate_melody(model, seed_sequence, length_to_generate=50, temperature=0.8):
model.eval()
current_seq = list(seed_sequence)
generated_melody = list(seed_sequence)
with torch.no_grad():
for _ in range(length_to_generate):
# Format input tensor to [1, current_seq_length]
input_tensor = torch.tensor([current_seq[-SEQ_LENGTH:]], dtype=torch.long)
logits, _ = model(input_tensor)
# Apply Temperature scaling to control creativity
word_weights = torch.softmax(logits / temperature, dim=-1).squeeze().numpy()
# Sample the next pitch token
next_pitch = np.random.choice(len(word_weights), p=word_weights)
generated_melody.append(next_pitch)
current_seq.append(next_pitch)
return generated_melody
# Example usage (Assuming ‘model’ is trained)
# seed = [60, 62, 64, 60] # Middle C major progression seed
# print(generate_melody(model, seed))
0 Comments