Borland & Djem
Hey Borland, what if we make a program that writes guitar riffs the way I jam—random, emotional, and unpredictable? Think code meets chaos.
Sounds like a fun challenge. Start by defining a small set of chord progressions and a scale. Then pick a tempo and use a random generator to choose note lengths and intervals within that scale. To keep it emotional, you can bias the random choices toward larger intervals or syncopated rhythms. Add a simple algorithm for a solo – maybe a Markov chain trained on some of your favorite riffs. That way the output feels like a natural jam but still unpredictable. Remember to test it with a loop so you can hear how the randomness plays out before you hit record. Good luck, and feel free to throw more specifics my way if you hit a snag.
Alright, let’s get concrete. 1. Chords: pick two or three progressions that feel emotional—like I‑V‑vi‑IV or ii‑V‑I in the key you like. 2. Scale: if you’re doing that key, just take the major or minor scale, keep the notes in a list. 3. Tempo: set a BPM that feels natural, maybe 80‑100 for a laid‑back vibe, 120‑140 for a tighter groove. 4. Random generator: use the language’s random library to pick a note length from 16th, 8th, 4th, and a pitch from the scale. 5. Bias: multiply the probability of picking a big interval (say a 7th or octave) by 1.5 and give syncopation a boost by favoring off‑beat positions. 6. Solo algorithm: build a simple Markov chain where each note leads to a set of next possible notes you’ve hand‑picked from your favorite riffs; keep the state small so it stays fluid. 7. Loop and listen: run the generator in a loop that writes MIDI or audio to a buffer, play it back, tweak the bias until the feel is right. 8. Save and export: once you’re happy, export the sequence as a file or stream it to your DAW. Keep the code modular so you can swap out chord sets or scale quickly. If you hit a roadblock, let me know which part’s stuck and we’ll hammer it out. Happy jamming!
Sounds solid. Just a quick tweak: when you build the Markov chain, keep the transition table small—maybe 3–4 possible next notes—so the solo stays loose instead of getting stuck. Also, for the bias you can use a weight array for each interval size; that way you can fine‑tune without rewriting the random logic. Happy coding, and drop me a snippet if you need a second set of eyes.
Got it—small transition tables keep the flow wild, weights let me tweak the feel without rewiring everything. Drop the snippet when you’re ready, I’ll give it a quick listen. Happy coding, and keep that creative spark burning.
Here’s a minimal Python skeleton that puts everything together.
Just paste it into a file, run it, and tweak the values until the riff feels right.
```python
import random
import mido
from mido import Message, MidiFile, MidiTrack
# 1. Chord progressions
progressions = [
['C', 'G', 'Am', 'F'], # I‑V‑vi‑IV in C
['Dm', 'G', 'C'] # ii‑V‑I in C
]
# 2. Scale notes (C major)
scale = ['C', 'D', 'E', 'F', 'G', 'A', 'B']
# 3. Tempo
bpm = 90
ticks_per_beat = 480
# 4. Random generator setup
note_durations = [ticks_per_beat // 4, ticks_per_beat // 2, ticks_per_beat]
interval_weights = {1:1, 2:1, 3:1.5, 4:1.5} # weights for intervals
# 5. Helper to get pitch class from note name
note_map = {
'C': 60, 'C#': 61, 'Db': 61, 'D': 62, 'D#': 63, 'Eb': 63,
'E': 64, 'F': 65, 'F#': 66, 'Gb': 66, 'G': 67, 'G#': 68,
'Ab': 68, 'A': 69, 'A#': 70, 'Bb': 70, 'B': 71
}
def note_from_name(name, octave=4):
return note_map[name] + (octave - 4) * 12
# 6. Markov-like solo table (hand‑picked transitions)
solo_table = {
'C': ['E', 'G', 'A'],
'D': ['F', 'A', 'C'],
'E': ['G', 'Bb', 'D'],
'F': ['A', 'C', 'E'],
'G': ['B', 'D', 'F'],
'A': ['C', 'E', 'G'],
'B': ['D', 'F', 'A']
}
# 7. Generate a riff
midi = MidiFile(ticks_per_beat=ticks_per_beat)
track = MidiTrack()
midi.tracks.append(track)
track.append(mido.MetaMessage('set_tempo', tempo=mido.bpm2tempo(bpm)))
# Pick a progression
prog = random.choice(progressions)
for chord_root in prog:
# Play the chord as a block (simplified)
for note_name in chord_root:
pitch = note_from_name(note_name)
track.append(Message('note_on', note=pitch, velocity=64, time=0))
for note_name in chord_root:
pitch = note_from_name(note_name)
track.append(Message('note_off', note=pitch, velocity=64, time=0))
# Solo section
current = random.choice(scale)
for _ in range(8):
next_notes = solo_table.get(current, scale)
interval = random.choices(range(1,5), weights=[interval_weights[i] for i in range(1,5)])[0]
next_pitch_name = next_notes[min(interval-1, len(next_notes)-1)]
current = next_pitch_name
dur = random.choice(note_durations)
pitch = note_from_name(current)
track.append(Message('note_on', note=pitch, velocity=80, time=0))
track.append(Message('note_off', note=pitch, velocity=80, time=dur))
midi.save('random_riff.mid')
```
Run it, load the resulting `random_riff.mid` into your DAW, and you’ll hear a random, emotional riff. Feel free to swap out the scale, tweak the weights, or add more chord progressions. Happy jamming!
That looks solid, just give the solo a bit more swing by bumping the 3rd and 4th interval weights a notch higher. Toss in a couple of seventh chords for extra tension and the riff will punch harder. Once you hit record, tweak the timing a bit so the syncopation lands on the off‑beats—just enough to keep the groove alive. Happy jamming, and hit me up if the random machine starts glitching.
Here’s a quick tweak to swing the solo a bit more.
Just bump the 3rd and 4th interval weights and add a handful of seventh‑chord roots to the chord list. I’ve also added a small bias to fire off‑beat notes.
```python
# … after the interval_weights line
interval_weights = {1:1, 2:1, 3:1.7, 4:1.7} # swing
# Add seventh chords to progressions
progressions = [
['C', 'G7', 'Am', 'F'],
['Dm', 'G7', 'C']
]
# Off‑beat bias for durations
note_durations = [ticks_per_beat // 4, ticks_per_beat // 2, ticks_per_beat]
offbeat_offsets = [ticks_per_beat // 2] # push some notes onto the 2nd and 4th sub‑beat
# In the solo loop, sprinkle an off‑beat when choosing duration
dur = random.choice(note_durations)
if random.random() < 0.3: # 30 % chance to shift
dur += random.choice(offbeat_offsets)
# ... rest of code unchanged
```
Run it again, listen for the added tension, and feel free to dial the 30 % off‑beat bias up or down. If anything hiccups, let me know! Happy jamming.