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.
- docs/beatrecipe_docs.txt +80 -0
- rosabeats/__init__.py +23 -0
- rosabeats/beatrecipe_processor.py +523 -0
- rosabeats/beatswitch.py +256 -0
- rosabeats/rosabeats.py +996 -0
- rosabeats/rosabeats_shell.py +387 -0
- rosabeats/segment_song.py +181 -0
- rosabeats-0.1.3.dist-info/METADATA +158 -0
- rosabeats-0.1.3.dist-info/RECORD +16 -0
- rosabeats-0.1.3.dist-info/WHEEL +5 -0
- rosabeats-0.1.3.dist-info/entry_points.txt +5 -0
- rosabeats-0.1.3.dist-info/licenses/LICENSE.md +7 -0
- rosabeats-0.1.3.dist-info/top_level.txt +3 -0
- scripts/reverse_beats_in_bars_rosa.py +48 -0
- scripts/shuffle_bars_rosa.py +35 -0
- scripts/shuffle_beats_rosa.py +29 -0
rosabeats/beatswitch.py
ADDED
|
@@ -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()
|