1+ #!/usr/bin/env python3
2+ """
3+ Isobar Playground - Quick MIDI Experimentation Environment
4+
5+ A ready-to-go environment for live coding and experimenting with isobar patterns.
6+ Start coding immediately with pre-configured MIDI output and helpful shortcuts.
7+
8+ Usage:
9+ python playground.py
10+
11+ Quick Commands:
12+ play(pattern, **kwargs) - Schedule pattern immediately
13+ stop_all() - Stop all playing tracks
14+ set_tempo(bpm) - Change tempo
15+ show_devices() - List available MIDI devices
16+
17+ Example:
18+ play(PSequence([60, 64, 67]), duration=0.5)
19+ play(PChoice([72, 75, 79]) + PRandom(-12, 12), channel=1)
20+ """
21+
22+ from isobar import *
23+ import logging
24+ import time
25+ import atexit
26+
27+ # Global references for easy access
28+ timeline = None
29+ tracks = []
30+
31+ def setup ():
32+ """Initialize the playground environment"""
33+ global timeline
34+
35+ # Set up logging for feedback
36+ logging .basicConfig (level = logging .INFO , format = "[%(asctime)s] %(message)s" )
37+
38+ # Show available MIDI devices
39+ print ("🎹 Isobar Playground - MIDI Experimentation Environment" )
40+ print ("=" * 60 )
41+ show_devices ()
42+
43+ # Create timeline with error handling for stability
44+ timeline = Timeline (tempo = 120 , ignore_exceptions = True )
45+ timeline .start ()
46+
47+ print (f"\n ✅ Timeline started at 120 BPM" )
48+ print ("💡 Type 'help_playground()' for commands and examples" )
49+
50+ # Cleanup on exit
51+ atexit .register (cleanup )
52+
53+ def show_devices ():
54+ """Display available MIDI output devices"""
55+ from isobar .io import get_midi_output_names
56+ devices = get_midi_output_names ()
57+ print (f"\n 📱 Available MIDI Devices ({ len (devices )} ):" )
58+ if devices :
59+ for i , name in enumerate (devices ):
60+ print (f" { i } : { name } " )
61+ else :
62+ print (" No MIDI devices found. Consider:" )
63+ print (" - Enable IAC Driver in Audio MIDI Setup (macOS)" )
64+ print (" - Connect a hardware MIDI device" )
65+ print (" - Use virtual MIDI software" )
66+
67+ def play (pattern , duration = 1 , velocity = 80 , channel = 0 , ** kwargs ):
68+ """
69+ Quick function to play a pattern immediately
70+
71+ Args:
72+ pattern: The pattern to play (note values)
73+ duration: Note duration pattern (default 1)
74+ velocity: Note velocity pattern (default 80)
75+ channel: MIDI channel (default 0)
76+ **kwargs: Additional track parameters
77+
78+ Returns:
79+ Track reference for further manipulation
80+ """
81+ global timeline , tracks
82+
83+ if timeline is None :
84+ print ("❌ Timeline not initialized. Run setup() first." )
85+ return None
86+
87+ # Build event dict
88+ event_dict = {
89+ "note" : pattern ,
90+ "duration" : duration ,
91+ "velocity" : velocity ,
92+ "channel" : channel ,
93+ ** kwargs
94+ }
95+
96+ # Schedule the pattern
97+ track = timeline .schedule (event_dict )
98+ tracks .append (track )
99+
100+ print (f"🎵 Playing pattern on channel { channel } " )
101+ return track
102+
103+ def stop_all ():
104+ """Stop all currently playing tracks"""
105+ global timeline , tracks
106+
107+ if timeline :
108+ for track in tracks :
109+ if track and hasattr (track , 'stop' ):
110+ track .stop ()
111+ tracks .clear ()
112+ print ("🛑 All tracks stopped" )
113+
114+ def set_tempo (bpm ):
115+ """Change the global tempo"""
116+ global timeline
117+
118+ if timeline :
119+ timeline .tempo = bpm
120+ print (f"🎯 Tempo set to { bpm } BPM" )
121+
122+ def cleanup ():
123+ """Clean up resources on exit"""
124+ global timeline
125+
126+ if timeline :
127+ stop_all ()
128+ timeline .stop ()
129+ print ("\n 👋 Playground session ended" )
130+
131+ def help_playground ():
132+ """Show playground commands and examples"""
133+ print ("""
134+ 🎹 Isobar Playground Commands:
135+
136+ Basic Functions:
137+ play(pattern, **kwargs) - Play a pattern immediately
138+ stop_all() - Stop all tracks
139+ set_tempo(bpm) - Change tempo
140+ show_devices() - List MIDI devices
141+ help_playground() - Show this help
142+
143+ Quick Pattern Examples:
144+
145+ # Simple sequences
146+ play(PSequence([60, 64, 67, 72]))
147+ play(PRange(60, 73))
148+
149+ # Rhythmic patterns
150+ play(PSequence([36]), duration=PBjorklund(3, 8))
151+ play(PChoice([60, 64, 67]), duration=PChoice([0.25, 0.5, 1]))
152+
153+ # Random and evolving
154+ play(PChoice([60, 64, 67]) + PRandom(-12, 12))
155+ play(PBrown(60, 12, 2), duration=0.25)
156+ play(PWalk([60, 64, 67, 70], 1))
157+
158+ # Multiple channels
159+ play(PSequence([36, 38]), channel=9) # Drums
160+ play(PChoice([48, 50, 53]), channel=1, velocity=60) # Bass
161+
162+ # Control changes
163+ play(PSequence([60]), control={74: PSine(64, 32, 8)}) # Filter sweep
164+
165+ Common Pattern Classes:
166+ PSequence(list) - Play list in order
167+ PChoice(list) - Random choice from list
168+ PRange(start, stop, step) - Numeric range
169+ PRandom(min, max) - Random numbers
170+ PBrown(start, max, step) - Brownian motion
171+ PWalk(values, step_size) - Random walk through values
172+ PBjorklund(hits, length) - Euclidean rhythms
173+ PSine(center, amplitude, period) - Sine wave
174+
175+ Shortcuts for live coding:
176+ C4 = 60 # Middle C
177+ KICK = 36 # Standard kick drum
178+ SNARE = 38 # Standard snare drum
179+
180+ Try:
181+ play(PSequence([C4, C4+4, C4+7]), duration=0.5)
182+ """ )
183+
184+ # Helpful constants for live coding
185+ C4 = 60
186+ D4 = 62
187+ E4 = 64
188+ F4 = 65
189+ G4 = 67
190+ A4 = 69
191+ B4 = 71
192+ C5 = 72
193+
194+ KICK = 36
195+ SNARE = 38
196+ HIHAT = 42
197+ OPENHAT = 46
198+ CRASH = 49
199+
200+ # Auto-setup when imported or run as script
201+ setup ()
202+
203+ # Interactive mode when run as main script
204+ if __name__ == "__main__" :
205+ print ("\n 🚀 Quick Start Examples:" )
206+ print (" play(PSequence([60, 64, 67, 72]))" )
207+ print (" play(PChoice([60, 64, 67]) + PRandom(-12, 12), duration=0.25)" )
208+ print (" play(PSequence([36]), duration=PBjorklund(3, 8), channel=9)" )
209+ print ("\n ⌨️ Press Ctrl+C to exit" )
210+
211+ try :
212+ # Keep the script running for interactive use
213+ while True :
214+ time .sleep (1 )
215+ except KeyboardInterrupt :
216+ print ("\n 🛑 Stopping playground..." )
217+ cleanup ()
0 commit comments