rosabeats 0.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,256 @@
1
+ #!/usr/bin/env python
2
+
3
+ import sys
4
+ import random
5
+ import os.path
6
+ import argparse
7
+ import rosabeats
8
+
9
+
10
+ class BeatSwitcher(rosabeats.rosabeats):
11
+ """A class for generating beat recipes by switching between forward and backward playback of beats.
12
+
13
+ This class extends rosabeats to generate beat recipes (`.br` files) that describe
14
+ a dynamic remix by alternating between playing beats forward and backward in random lengths.
15
+ The resulting `.br` file can be processed using beatrecipe-processor to create the actual
16
+ audio remix.
17
+
18
+ The beat recipe maintains the original beat structure while creating new rhythmic
19
+ patterns through alternating forward and backward playback of beat segments.
20
+
21
+ Attributes:
22
+ infile (str): Path to input audio file
23
+ outfile (str): Path to output beat recipe file (.br)
24
+ firstfull (int): Index of first full bar
25
+ fmin (int): Minimum number of forward beats
26
+ fmax (int): Maximum number of forward beats
27
+ bmin (int): Minimum number of backward beats
28
+ bmax (int): Maximum number of backward beats
29
+ """
30
+
31
+ def __init__(self, infile, debug=False):
32
+ """Initialize the BeatSwitcher.
33
+
34
+ Args:
35
+ infile (str): Path to input audio file
36
+ debug (bool, optional): Enable debug mode
37
+ """
38
+ self.infile = infile
39
+ self.debug = debug
40
+
41
+ # Initialize parent class
42
+ super().__init__(self.infile, debug=self.debug)
43
+
44
+ # Initialize instance variables
45
+ self.outfile = None
46
+ self.firstfull = None
47
+ self.fmin = None
48
+ self.fmax = None
49
+ self.bmin = None
50
+ self.bmax = None
51
+
52
+ def setup(self, outfile, firstfull):
53
+ """Set up the beat recipe configuration.
54
+
55
+ Args:
56
+ outfile (str): Path to output beat recipe file (.br)
57
+ firstfull (int): Index of first full bar
58
+ """
59
+ # Configure output file
60
+ self.outfile = outfile
61
+ self.enable_output_beats(self.outfile)
62
+
63
+ # Configure beat tracking
64
+ self.firstfull = firstfull
65
+ self.track_beats(firstfull=firstfull)
66
+
67
+ # Disable WAV output and playback
68
+ self.disable_output_save()
69
+ self.disable_output_play()
70
+
71
+ def play_byswitchingbeatdirection(self, fmin=8, fmax=16, bmin=4, bmax=8):
72
+ """Generate a beat recipe by alternating between forward and backward playback.
73
+
74
+ This method generates a beat recipe by:
75
+ 1. Starting from the first full bar
76
+ 2. Alternating between playing beats forward and backward
77
+ 3. Using random lengths for each direction
78
+ 4. Continuing until the end of the song
79
+
80
+ The resulting beat recipe can be processed using beatrecipe-processor
81
+ to create the actual audio remix.
82
+
83
+ Args:
84
+ fmin (int, optional): Minimum number of forward beats
85
+ fmax (int, optional): Maximum number of forward beats
86
+ bmin (int, optional): Minimum number of backward beats
87
+ bmax (int, optional): Maximum number of backward beats
88
+ """
89
+ if self.beat_samples is None:
90
+ self.gen_beat_samples()
91
+
92
+ # Start from first full bar
93
+ curr_beat = self.firstfullbar
94
+ song_over = False
95
+ direction = "r" # Start with reverse direction
96
+
97
+ # Write initial beats up to first full bar
98
+ if curr_beat > 0:
99
+ for b in range(curr_beat):
100
+ print(">%d " % curr_beat, end="", flush=True)
101
+ self.play_beat(b, silent=True)
102
+
103
+ # Main recipe generation loop
104
+ while not song_over:
105
+ # Switch direction and determine number of beats
106
+ if direction == "r":
107
+ direction = "f"
108
+ num_beats = random.randint(int(fmin / 2), int(fmax / 2)) * 2
109
+ self.write_out("# %d forward beats" % num_beats)
110
+ else:
111
+ direction = "r"
112
+ num_beats = random.randint(int(bmin / 2), int(bmax / 2)) * 2
113
+ self.write_out("# %d reverse beats" % num_beats)
114
+
115
+ # Print progress
116
+ print(
117
+ "(%.02f%%) [%d%s] "
118
+ % ((curr_beat / (self.total_beats - 1)) * 100, num_beats, direction),
119
+ end="",
120
+ flush=True,
121
+ )
122
+
123
+ # Generate beats in current direction
124
+ for x in range(num_beats):
125
+ if direction == "f":
126
+ curr_beat += 1
127
+ if curr_beat >= self.total_beats - 1:
128
+ song_over = True
129
+ break
130
+ print(">%d " % curr_beat, end="", flush=True)
131
+ else:
132
+ curr_beat -= 1
133
+ if curr_beat < 0:
134
+ break
135
+ print("<%d " % curr_beat, end="", flush=True)
136
+
137
+ self.play_beat(curr_beat, silent=True)
138
+
139
+ print(flush=True)
140
+
141
+ # Clean up
142
+ self.shutdown()
143
+
144
+ def set_parameters(self, fmin=8, fmax=16, bmin=4, bmax=8):
145
+ """Set the beat switching parameters.
146
+
147
+ Args:
148
+ fmin (int, optional): Minimum number of forward beats
149
+ fmax (int, optional): Maximum number of forward beats
150
+ bmin (int, optional): Minimum number of backward beats
151
+ bmax (int, optional): Maximum number of backward beats
152
+ """
153
+ self.fmin = fmin
154
+ self.fmax = fmax
155
+ self.bmin = bmin
156
+ self.bmax = bmax
157
+
158
+ def run(self):
159
+ """Run the beat recipe generation process."""
160
+ self.play_byswitchingbeatdirection(self.fmin, self.fmax, self.bmin, self.bmax)
161
+
162
+
163
+ def get_default_output_path(input_file):
164
+ """Generate default output path based on input file.
165
+
166
+ Args:
167
+ input_file (str): Path to input file
168
+
169
+ Returns:
170
+ str: Default output path with _bs.br suffix
171
+ """
172
+ base, _ = os.path.splitext(input_file)
173
+ return f"{base}_bs.br"
174
+
175
+
176
+ def parse_args():
177
+ """Parse command line arguments.
178
+
179
+ Returns:
180
+ argparse.Namespace: Parsed command line arguments
181
+ """
182
+ parser = argparse.ArgumentParser(
183
+ description="""Generate a beat recipe (.br file) by switching between forward and backward playback of beats.
184
+
185
+ The generated beat recipe can be processed using beatrecipe-processor to create the actual audio remix.
186
+ This tool only generates the recipe, not the final audio file.""",
187
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter
188
+ )
189
+
190
+ # Required arguments
191
+ parser.add_argument(
192
+ "input_file",
193
+ help="Input audio file to process"
194
+ )
195
+
196
+ # Optional arguments
197
+ parser.add_argument(
198
+ "-o", "--output",
199
+ help="Output beat recipe file (.br) - defaults to input filename with _bs.br suffix"
200
+ )
201
+ parser.add_argument(
202
+ "--fmin", type=int, default=8,
203
+ help="Minimum number of forward beats"
204
+ )
205
+ parser.add_argument(
206
+ "--fmax", type=int, default=16,
207
+ help="Maximum number of forward beats"
208
+ )
209
+ parser.add_argument(
210
+ "--bmin", type=int, default=4,
211
+ help="Minimum number of backward beats"
212
+ )
213
+ parser.add_argument(
214
+ "--bmax", type=int, default=8,
215
+ help="Maximum number of backward beats"
216
+ )
217
+ parser.add_argument(
218
+ "--firstfull", type=int, default=0,
219
+ help="First full bar index"
220
+ )
221
+ parser.add_argument(
222
+ "--debug", action="store_true",
223
+ help="Enable debug mode"
224
+ )
225
+
226
+ return parser.parse_args()
227
+
228
+
229
+ def main():
230
+ """Main function for beatswitch command-line tool.
231
+
232
+ Example:
233
+ # Generate a beat recipe with default output name
234
+ beatswitch input.wav
235
+
236
+ # Generate a beat recipe with custom output name
237
+ beatswitch input.wav -o custom.br
238
+
239
+ # Convert the recipe to audio using beatrecipe-processor
240
+ beatrecipe-processor input.wav output.br output.wav
241
+ """
242
+ args = parse_args()
243
+
244
+ # Determine output file path
245
+ output_file = args.output if args.output else get_default_output_path(args.input_file)
246
+ print(f"Output file: {output_file}")
247
+
248
+ # Create and run beat switcher
249
+ bs = BeatSwitcher(args.input_file, debug=args.debug)
250
+ bs.setup(output_file, args.firstfull)
251
+ bs.set_parameters(args.fmin, args.fmax, args.bmin, args.bmax)
252
+ bs.run()
253
+
254
+
255
+ if __name__ == "__main__":
256
+ main()