Skip to content

Commit

Permalink
Add proper multitrack support
Browse files Browse the repository at this point in the history
  • Loading branch information
marcan committed Nov 27, 2017
1 parent 2d63c60 commit 8c3cbf9
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 19 deletions.
2 changes: 1 addition & 1 deletion blitzloop/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def update_params():
mpv.set_speed(1.0 / (2**(qe.speed / 12.0)))
mpv.set_pitch(2**(qe.pitch / 12.0))
for i, j in enumerate(qe.channels):
mpv.set_channel(i, j / 10.0)
mpv.set_channel(i, j["volume"] / 10.0)
mpv.set_pause(qe.pause)

update_params()
Expand Down
25 changes: 16 additions & 9 deletions blitzloop/play.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@

speed_i = 0
pitch_i = 0
vocals_i = 10
channels_i = s.channel_defaults

if opts.offset:
mpv.seek_to(opts.offset)
Expand Down Expand Up @@ -84,6 +84,9 @@ def render():

pause = False

CH_UP = b"+456"
CH_DOWN = b"-123"

def key(k):
import OpenGL.GLUT as glut
global speed_i, pitch_i, vocals_i, pause
Expand All @@ -108,14 +111,18 @@ def key(k):
pitch_i -= 1
print("Pitch: %d" % pitch_i)
mpv.set_pitch(2**(pitch_i/12.0))
elif k == b'+' and vocals_i < 30:
vocals_i += 1
print("Vocals: %d" % vocals_i)
mpv.set_channel(0, vocals_i/10.0)
elif k == b'-' and vocals_i > 0:
vocals_i -= 1
print("Vocals: %d" % vocals_i)
mpv.set_channel(0, vocals_i/10.0)
elif k in CH_UP:
idx = CH_UP.index(k)
if len(channels_i) > idx and channels_i[idx] < 30:
channels_i[idx] += 1
print("Channel %d: %d" % (idx, channels_i[idx]))
mpv.set_channel(idx, channels_i[idx]/10.0)
elif k in CH_DOWN:
idx = CH_DOWN.index(k)
if len(channels_i) > idx and channels_i[idx] > 0:
channels_i[idx] -= 1
print("Channel %d: %d" % (idx, channels_i[idx]))
mpv.set_channel(idx, channels_i[idx]/10.0)
elif k == glut.GLUT_KEY_LEFT:
mpv.seek(-10)
elif k == glut.GLUT_KEY_RIGHT:
Expand Down
6 changes: 5 additions & 1 deletion blitzloop/res/web/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,13 @@ app.controller('SongDetailCtrl', function($scope, $rootScope, $routeParams, $htt
$http.get('/song/' + $routeParams.songId).success(function(data) {
$scope.song = data;
$scope.coverUrl = "/song/" + data.id + "/cover/200" + "?" + g_cfg.nonce;
var channels = [];
for (var i = 0; i < data.channels.length; i++) {
channels.push({"volume": data.channels[i]});
}
$scope.song.config = {
variant: 0,
channels: [3],
channels: channels,
speed: 0,
pitch: 0,
pause: false
Expand Down
4 changes: 2 additions & 2 deletions blitzloop/res/web/partials/song.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
<slider ng-model="song.config.pitch" min="-12" max="12" plus>Pitch</slider>
<slider ng-model="song.config.speed" min="-12" max="12" plus>Tempo</slider>
</div>
<div class="right" ng-show="song.channels > 0">
<slider ng-model="song.config.channels[0]" min="0" max="20">Vocals</slider>
<div class="right" ng-show="song.channels.length > 0">
<slider ng-repeat="c in song.config.channels" ng-model="c.volume" min="0" max="20">{{$parent.song.channel_names[$parent.$index]}}</slider>
</div>
<div class="wide"></div>
</div>
Expand Down
23 changes: 23 additions & 0 deletions blitzloop/song.py
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,29 @@ def aspect(self):
else:
return fractions.Fraction(self.song["aspect"])

@property
def channels(self):
return int(self.song.get("channels", "1"))

@property
def channel_defaults(self):
if "channel_defaults" in self.song:
return [int(i) for i in self.song["channel_defaults"].split(",")]
else:
return ([3] + [0] * self.channels)[:-1]

@property
def channel_names(self):
if "channel_names" in self.song:
return self.song["channel_names"].split(",")
else:
if self.channels == 0:
return []
elif self.channels == 1:
return ["Vocals"]
else:
return ["Ch %d" % (i+1) for i in range(self.channels)]

def get_lyric_snippet(self, variant_id, length=100):
variant = self.variants[variant_id]
tags = set(i for i in variant.tag_list if variant.tags[i].edge == TagInfo.BOTTOM)
Expand Down
4 changes: 3 additions & 1 deletion blitzloop/songlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ def __init__(self, song):
self.song = song
self.qid = None
self.variant = 0
self.channels = [3]
self.channels = []
for i in range(song.channels):
self.channels.append({"volume": i})
self.speed = 0
self.pitch = 0
self.pause = False
Expand Down
8 changes: 5 additions & 3 deletions blitzloop/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ def get_song(id):
"id": id,
"meta": get_song_meta(song),
"variants": get_song_variants(song),
"channels": int(song.song.get("channels", 1))
"channels": song.channel_defaults,
"channel_names": song.channel_names,
}

@route("/song/<id:int>/cover/<size:int>")
Expand Down Expand Up @@ -173,8 +174,9 @@ def queue_get(qid):
"qid": qid,
"meta": get_song_meta(qe.song),
"variants": get_song_variants(qe.song),
"channels": int(qe.song.song.get("channels", 1)),
"config": get_qe_config(qe)
"channels": qe.song.channel_defaults,
"channel_names": qe.song.channel_names,
"config": get_qe_config(qe),
}

def apply_qe(qe, json):
Expand Down
8 changes: 6 additions & 2 deletions docs/songfiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ This section defines the audio/video content of the song.
* `aspect`: Forces a specific aspect ratio for the song, specified as a rational or decimal number (e.g. `16/9` is valid). This does not stretch the video itself. Instead, this defines the aspect ratio of the song display. By default, the song aspect ratio is determined from the video file, lyrics are rendered within the bounds of that aspect ratio, and then the result is letterboxed or pillarboxed to match the display aspect. Specifying this value will force the aspect ratio of the song display: `16/9` for a 4:3 video will result in the video being cropped to 16:9, then the song will be rendered on the 16:9 canvas, which will then be letterboxed or pillarboxed to match the display. This is mainly useful for 16:9 source videos that are already letterboxed into 4:3: instead of having the video be pillarboxed again on a widescreen display, this crops it and causes it to display full screen on a 16:9 display, and makes the lyrics fit within the bounds of the image.
* `cover`: Album cover image, for the remote control UI. This should be nearly square, as currently aspect is not preserved (this may change in the future).
* `channels`: The number of additional stereo channels expected in the audio file. Defaults to 1, for a 4-track karaoke audio track. Specify 0 for a standard stereo track. See the following section for details.
* `channel_names`: Comma-separated list of channel names. Important when `channels` is greater than 1.
* `channel_defaults`: Comma-separated list of default channel volumes, in units of 1/10th full volume. Defaults to 3 for the first channel and 0 for the rest.
* `fade_in`: Time over which to fade in the video at the beginning of the song, in seconds.
* `fade_out`: Time over which to fade out the video at the end of the song, in seconds.
* `volume`: Adjust the playback volume of the audio (defaults to 1, linear scale). Eventually there should be some tool to automatically calculate this based on ReplayGain normalization.
Expand All @@ -57,9 +59,11 @@ The reason why this case differs from the n > 2 case is that most songs are avai

There is a rather primitive tool to help align the tracks into phase in the [blitzloop-tools](https://github.com/marcan/blitzloop-tools) repo.

#### `channels=<n>` for <n> > 2
#### `channels=<n>` for <n> >= 2

The file should contain n + 1 stereo pairs. The first stereo pair should be the instrumental version of the song, and each subsequent stereo pair represents an optional channel that will be mixed in (added) to the base instrumental track. The controls allow for mixing volumes from 0% to 200%. This could be used to have multiple vocal tracks that can be independently mixed in.
The file should contain n + 1 stereo pairs. The first stereo pair should be the instrumental version of the song, and each subsequent stereo pair represents an optional channel that will be mixed in (added) to the base instrumental track. The controls allow for mixing volumes from 0% to 200%. This could be used to have multiple vocal tracks that can be independently mixed in, or to have a separate guide melody track.

In this case, the `[Song]` section should also have a `channel_names` entry giving user-friendly names to the channels, and you may also want a `channel_defaults` to set the default volumes.

## `[Timing]`

Expand Down

0 comments on commit 8c3cbf9

Please sign in to comment.