Borland & Djem
Djem 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.
Borland Borland
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.
Djem Djem
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!
Borland Borland
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.
Djem Djem
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.
Borland Borland
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!
Djem Djem
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.
Borland Borland
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.