Andybeyond commited on
Commit
d9c7e7e
·
verified ·
1 Parent(s): b970e1a

Create notebooks/melody_development.ipynb

Browse files

Add starting melody_development notebook code.

Files changed (1) hide show
  1. notebooks/melody_development.ipynb +138 -0
notebooks/melody_development.ipynb ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ # Melody Generation Model Development
3
+ # Project: Opentunes.ai
4
+
5
+ This notebook implements a Transformer-based melody generation model.
6
+ The model takes text prompts and generates musical melodies in MIDI format.
7
+
8
+ Key Features:
9
+ - Text-to-melody generation
10
+ - MIDI file handling
11
+ - Transformer architecture
12
+ - Training pipeline integration with HuggingFace
13
+
14
+ Note: This is a starting point and might need adjustments based on:
15
+ - Specific musical requirements
16
+ - Available training data
17
+ - Computational resources
18
+ - Desired output format
19
+ """
20
+
21
+ import torch
22
+ import torch.nn as nn
23
+ from transformers import (
24
+ AutoModelForAudio,
25
+ AutoTokenizer,
26
+ Trainer,
27
+ TrainingArguments
28
+ )
29
+ import librosa
30
+ import numpy as np
31
+ import pandas as pd
32
+ import music21
33
+ from pathlib import Path
34
+ import json
35
+ import wandb # for experiment tracking
36
+
37
+ # =====================================
38
+ # 1. Data Loading and Preprocessing
39
+ # =====================================
40
+
41
+ class MelodyDataset(torch.utils.data.Dataset):
42
+ """
43
+ Custom Dataset class for handling melody data.
44
+
45
+ This class:
46
+ - Loads MIDI files from a directory
47
+ - Converts MIDI files to sequences of notes and durations
48
+ - Provides data in format suitable for model training
49
+
50
+ Args:
51
+ data_dir (str): Directory containing MIDI files
52
+ max_length (int): Maximum sequence length (default: 512)
53
+
54
+ Features:
55
+ - Handles variable-length MIDI files
56
+ - Converts complex MIDI structures to simple note sequences
57
+ - Implements efficient data loading and preprocessing
58
+ """
59
+
60
+ def __init__(self, data_dir, max_length=512):
61
+ self.data_dir = Path(data_dir)
62
+ self.max_length = max_length
63
+ self.midi_files = list(self.data_dir.glob("*.mid"))
64
+
65
+ # Initialize tokenizer for text prompts
66
+ self.tokenizer = AutoTokenizer.from_pretrained("t5-small")
67
+ print(f"Found {len(self.midi_files)} MIDI files in {data_dir}")
68
+
69
+ def midi_to_sequence(self, midi_path):
70
+ """
71
+ Convert MIDI file to sequence of notes.
72
+
73
+ Args:
74
+ midi_path (Path): Path to MIDI file
75
+
76
+ Returns:
77
+ list: List of dictionaries containing note information
78
+ Each dict has 'pitch', 'duration', and 'offset'
79
+
80
+ Example output:
81
+ [
82
+ {'pitch': 60, 'duration': 1.0, 'offset': 0.0}, # Middle C, quarter note
83
+ {'pitch': 64, 'duration': 0.5, 'offset': 1.0}, # E, eighth note
84
+ ...
85
+ ]
86
+ """
87
+ score = music21.converter.parse(str(midi_path))
88
+ notes = []
89
+
90
+ # Extract notes and their properties
91
+ for n in score.flat.notesAndRests:
92
+ if isinstance(n, music21.note.Note):
93
+ notes.append({
94
+ 'pitch': n.pitch.midi, # MIDI pitch number (0-127)
95
+ 'duration': n.duration.quarterLength, # Duration in quarter notes
96
+ 'offset': n.offset # Start time in quarter notes
97
+ })
98
+ return notes
99
+
100
+ def __getitem__(self, idx):
101
+ """
102
+ Get a single item from the dataset.
103
+
104
+ Args:
105
+ idx (int): Index of the item
106
+
107
+ Returns:
108
+ dict: Dictionary containing:
109
+ - 'notes': Tensor of note pitches
110
+ - 'durations': Tensor of note durations
111
+
112
+ Note: Both tensors are padded/truncated to max_length
113
+ """
114
+ midi_file = self.midi_files[idx]
115
+ melody_sequence = self.midi_to_sequence(midi_file)
116
+
117
+ # Convert to tensors with padding/truncation
118
+ notes = torch.tensor([n['pitch'] for n in melody_sequence])
119
+ durations = torch.tensor([n['duration'] for n in melody_sequence])
120
+
121
+ # Pad or truncate sequences
122
+ if len(notes) < self.max_length:
123
+ # Pad with rest values
124
+ pad_length = self.max_length - len(notes)
125
+ notes = torch.cat([notes, torch.zeros(pad_length)])
126
+ durations = torch.cat([durations, torch.zeros(pad_length)])
127
+ else:
128
+ # Truncate to max_length
129
+ notes = notes[:self.max_length]
130
+ durations = durations[:self.max_length]
131
+
132
+ return {
133
+ 'notes': notes,
134
+ 'durations': durations,
135
+ }
136
+
137
+ def __len__(self):
138
+ return len(self.midi_files)