Esempio n. 1
0
def main_render():
    # Wait for element in queue
    print("Waiting for song to appear in queue...")
    qe = None
    with queue.lock:
        if len(queue) != 0:
            qe = queue[0]
    if not qe:
        idle_screen.reset()
        graphics.get_renderer().clear(0, 0, 0, 1)
        for f in idle_screen:
            audio_config.update()
            yield None
            graphics.get_renderer().clear(0, 0, 0, 1)
            if not qe:
                with queue.lock:
                    if len(queue) != 0:
                        qe = queue[0]
                        idle_screen.close()

    for i in range(2):
        yield None
        graphics.get_renderer().clear(0, 0, 0, 1)

    print("Loading audio/video...")
    mpv.load_song(qe.song)
    display.set_aspect(mpv.aspect)

    print("Laying out song...")
    renderer.reset()
    variant_key = list(qe.song.variants.keys())[qe.variant]
    song_layout = layout.SongLayout(qe.song, variant_key, renderer)
    print("Loaded.")

    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["volume"] / 10.0)
        mpv.set_pause(qe.pause)

    update_params()
    song_time = -10
    stopping = False
    while not (mpv.eof_reached() or (stopping and qe.pause)):
        while qe.commands:
            cmd, arg = qe.commands.pop(0)
            if cmd == "seek":
                mpv.seek(arg)
            elif cmd == "seekto":
                mpv.seek_to(arg)
        mpv.draw()
        mpv.poll()
        song_time = mpv.get_song_time() or song_time

        if qe.stop and not stopping:
            stopping = True
            mpv.fade_out = 2
            mpv.duration = min(mpv.duration, song_time + 2)

        if not stopping:
            mpv.draw_fade(song_time)

        speed = 2**(qe.speed / 12.0)
        renderer.draw(song_time + audio_config.headstart / 100.0 * speed,
                      song_layout)

        if stopping:
            fade = mpv.draw_fade(song_time)
            mpv.set_fadevol(max(fade * 1.3 - 0.3, 0))

        update_params()
        audio_config.update(qe.song)
        yield None
        mpv.flip()

    graphics.get_renderer().clear(0, 0, 0, 1)
    for i in range(2):
        yield None
        graphics.get_renderer().clear(0, 0, 0, 1)

    print("Song complete.")
    try:
        queue.pop(qe.qid)
    except (IndexError, KeyError):
        pass
    mpv.stop()
    display.set_aspect(None)
Esempio n. 2
0
    'ffmpeg_opts', metavar='OPTS', nargs=argparse.REMAINDER, help='ffmpeg options')
opts = util.get_opts()

opts.display = "surfaceless"
opts.mpv_ao = "null"
if not opts.video:
    opts.mpv_vo = "null"

s = song.Song(opts.songpath)

display = graphics.Display(opts.width, opts.height)

import OpenGL.GLES3 as gl

renderer = graphics.get_renderer().KaraokeRenderer(display)
layout = layout.SongLayout(s, list(s.variants.keys())[opts.variant], renderer)

# Get duration of the audio path
mpv = mpvplayer.Player(display)
mpv.load_song(s)
duration = mpv.duration or mpv.file_duration

# Now run for rendering using only video
mpv = mpvplayer.Player(display, rendering=True)
mpv.load_song(s)

if not opts.video:
    mpv.shutdown()
print("Song duration: %f" % duration)
if opts.length:
    duration = min(duration, opts.length)
Esempio n. 3
0
def entry():
    parser = util.get_argparser()
    parser.add_argument('songpath',
                        metavar='SONGPATH',
                        help='path to the song file')
    parser.add_argument('--show-timings',
                        dest='st',
                        action='store_true',
                        help='show mpv timings')
    parser.add_argument('--offset',
                        type=float,
                        default=0.0,
                        help='song offset')
    parser.add_argument('--variant', type=int, default=0, help='song variant')
    opts = util.get_opts()

    fullscreen = opts.fullscreen
    s = song.Song(opts.songpath)

    headstart = 0.3

    if fullscreen:
        display = graphics.Display(1920, 1200, fullscreen, None)
    else:
        display = graphics.Display(1280, 720, fullscreen, None)
    print(display.width, display.height)

    mpv = mpvplayer.Player(display)
    mpv.load_song(s)

    display.set_aspect(mpv.aspect)

    renderer = graphics.get_renderer().KaraokeRenderer(display)
    song_layout = layout.SongLayout(s,
                                    list(s.variants.keys())[opts.variant],
                                    renderer)

    song_time = -10

    speed_i = 0
    pitch_i = 0
    channels_i = s.channel_defaults

    for idx, val in enumerate(channels_i):
        mpv.set_channel(idx, val / 10.0)

    if opts.offset:
        mpv.seek_to(opts.offset)

    def render():
        t = time.time()
        nonlocal song_time
        while not mpv.eof_reached():
            graphics.get_renderer().clear(0, 0, 0, 1)
            t1 = time.time()
            mpv.draw()
            dt = time.time() - t1
            mpv.poll()
            song_time = mpv.get_song_time() or song_time
            mpv.draw_fade(song_time)
            renderer.draw(song_time + headstart * 2**(speed_i / 12.0),
                          song_layout)
            yield None
            t2 = time.time()
            if opts.st:
                print("T:%7.3f/%7.3f B:%7.3f FPS:%.2f draw:%.3f" %
                      (song_time, mpv.duration, s.timing.time2beat(song_time),
                       (1.0 / (t2 - t)), dt))
            t = t2
            mpv.flip()
        mpv.shutdown()
        os._exit(0)

    pause = False

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

    def key(k):
        nonlocal speed_i, pitch_i, pause
        if k == 'KEY_ESCAPE':
            mpv.shutdown()
            os._exit(0)
        elif k == 'f':
            display.toggle_fullscreen()
        elif k == '[' and speed_i > -12:
            speed_i -= 1
            print("Speed: %d" % speed_i)
            mpv.set_speed(2**(-speed_i / 12.0))
        elif k == ']' and speed_i < 12:
            speed_i += 1
            print("Speed: %d" % speed_i)
            mpv.set_speed(2**(-speed_i / 12.0))
        elif k == 'KEY_UP' and pitch_i < 12:
            pitch_i += 1
            print("Pitch: %d" % pitch_i)
            mpv.set_pitch(2**(pitch_i / 12.0))
        elif k == 'KEY_DOWN' and pitch_i > -12:
            pitch_i -= 1
            print("Pitch: %d" % pitch_i)
            mpv.set_pitch(2**(pitch_i / 12.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 == 'KEY_LEFT':
            mpv.seek(-10)
        elif k == 'KEY_RIGHT':
            mpv.seek(10)
        elif k == ' ':
            pause = not pause
            t = time.time()
            mpv.set_pause(pause)
            print("P %.03f" % (time.time() - t))

    mpv.play()
    display.set_render_gen(render)
    display.set_keyboard_handler(key)
    display.main_loop()
    mpv.shutdown()
Esempio n. 4
0
    def _load_lyrics(self, s):
        telop = self.root.find("telop")

        renderer = graphics.get_renderer().KaraokeRenderer(self.display)
        lyt = layout.SongLayout(s,
                                list(s.variants.keys())[opts.variant],
                                renderer)

        lines = lyt.lines[song.TagInfo.BOTTOM]

        class Page(object):
            pass

        def ms(i):
            return str(int(round(i * 1000)))

        # Group lines into pages
        pages = []
        page = Page()
        page.lines = {}
        last = None
        for l in lines:
            if l.row in page.lines or (last and (l.row > last.row
                                                 or l.start > last.end)):
                pages.append(page)
                page = Page()
                page.lines = {}
            page.lines[l.row] = l
            last = l
        pages.append(page)

        # Compute page show/hide times
        prev = None
        pages2 = []
        for page in pages:
            lines = page.lines
            page.start = min(l.start for l in lines.values())
            page.min_start = min(l._start_t for l in lines.values())
            page.end = max(l.end for l in lines.values())
            page.min_end = max(l._end_t for l in lines.values())

            if prev and page.start < prev.end:
                page.start = min(page.min_start, prev.end)
                if prev and page.start < prev.end:
                    prev.end = max(prev.min_end, page.start)
                    if prev and page.start < prev.end:
                        li = " ".join(
                            repr(v.molecules[0][0].text)
                            for k, v in sorted(lines.items(), reverse=True))
                        raise Exception("overlapping lines! %r" % (li))
            prev = page
            pages2.append(page)

        # Generate XML
        for page in pages:
            pe = ET.Element("page")
            pe.append(self._tag("show_time", ms(page.start)))
            pe.append(self._tag("hide_time", ms(page.end)))
            pe.append(self._tag("paint_timing", "0"))
            pe.append(self._tag("layout", "xing_0"))

            t = page.min_start
            for i in range(max(page.lines.keys()), -1, -1):

                le = ET.Element("line")
                text = ""
                if i not in page.lines:
                    # dummy line
                    w = ET.Element("word")
                    w.append(self._tag("text", ""))
                    w.append(self._tag("start_time", ms(t)))
                    w.append(self._tag("end_time", ms(t)))
                    le.append(w)
                else:
                    line = page.lines[i]
                    assert len(line.molecules) == 1
                    mol, get_atom_time = line.molecules[0]
                    ruby = []
                    step = 0
                    for atom in mol.atoms:
                        start, end = get_atom_time(step, atom.steps)
                        step += atom.steps

                        w = ET.Element("word")
                        w.append(self._tag("text", atom.text))
                        w.append(self._tag("start_time", ms(start)))
                        w.append(self._tag("end_time", ms(end)))
                        le.append(w)

                        if atom.particles is not None:
                            edge = len(atom.text)
                            if atom.particle_edge:
                                edge = atom.particle_edge
                            rt = ""
                            for i in atom.particles:
                                rt += i.text
                            r = ET.Element("ruby")
                            r.append(self._tag("text", rt))
                            r.append(self._tag("start_pos", "%d" % len(text)))
                            r.append(
                                self._tag("end_pos",
                                          "%d" % (len(text) + edge - 1)))
                            ruby.append(r)

                        text += atom.text

                    for r in ruby:
                        le.append(r)

                    print(text)

                e = ET.Element("duet")
                e.append(self._tag("mark", "0"))
                e.append(self._tag("start_pos", "0"))
                e.append(self._tag("end_pos", "%d" % (len(text) - 1)))
                le.append(e)

                e = ET.Element("offset")
                e.append(self._tag("type", "0"))
                e.append(self._tag("offset", "0"))
                le.append(e)

                pe.append(le)

            telop.append(pe)
Esempio n. 5
0
    def _load_lyrics(self, s):
        telop = self.root.find("telop")

        renderer = graphics.get_renderer().KaraokeRenderer(self.display)
        lyt = layout.SongLayout(s,
                                list(s.variants.keys())[opts.variant],
                                renderer)

        lines = lyt.lines[song.TagInfo.BOTTOM]

        class Page(object):
            pass

        def ms(i):
            return str(int(round(i * 1000)))

        def color(rgb):
            r, g, b = rgb
            return "%d" % (r | (g << 8) | (b << 16))

        # Group lines into pages
        pages = []
        page = Page()
        page.lines = {}
        last = None
        for l in lines:
            if l.row in page.lines or (last and (l.row > last.row
                                                 or l.start > last.end)):
                pages.append(page)
                page = Page()
                page.lines = {}
            page.lines[l.row] = l
            last = l
        pages.append(page)

        # Compute page show/hide times
        prev = None
        pages2 = []
        for page in pages:
            lines = page.lines
            page.start = min(l.start for l in lines.values())
            page.min_start = min(l._start_t for l in lines.values())
            page.end = max(l.end for l in lines.values())
            page.min_end = max(l._end_t for l in lines.values())

            if prev and page.start < prev.end:
                page.start = min(page.min_start, prev.end)
                if prev and page.start < prev.end:
                    prev.end = max(prev.min_end, page.start)
                    if prev and page.start < prev.end:
                        li = " ".join(
                            repr(v.molecules[0][0].text)
                            for k, v in sorted(lines.items(), reverse=True))
                        raise Exception("overlapping lines! %r" % (li))
            prev = page
            pages2.append(page)

        # Generate XML
        for page in pages:
            pe = ET.Element("page")
            pe.append(self._tag("show_time", ms(page.start)))
            pe.append(self._tag("hide_time", ms(page.end)))
            pe.append(self._tag("paint_timing", "0"))
            pe.append(self._tag("layout", "xing_0"))

            t = page.min_start
            styles = None
            for i in range(max(page.lines.keys()), -1, -1):
                le = ET.Element("line")
                text = ""
                if i not in page.lines:
                    if styles:
                        styles = [[styles[-1][0], 0, 0]]
                    else:
                        styles = [[
                            page.lines.values()[0].molecules[0].style, 0, 0
                        ]]
                    # dummy line
                    w = ET.Element("word")
                    w.append(self._tag("text", " "))
                    w.append(self._tag("start_time", ms(t)))
                    w.append(self._tag("end_time", ms(t)))
                    le.append(w)
                    text = " "
                    width = cwidth = 0
                    align = 0
                else:
                    line = page.lines[i]
                    align = line.align
                    ruby = []
                    styles = []

                    for idx, instance in enumerate(line.molecules):
                        mol = instance.molecule
                        step = 0
                        start_pos = len(text)
                        for atom in mol.atoms:
                            start, end = instance.get_atom_time(
                                step, atom.steps)
                            t = max(t, end)
                            step += atom.steps

                            w = ET.Element("word")
                            w.append(self._tag("text", atom.text))
                            w.append(self._tag("start_time", ms(start)))
                            w.append(self._tag("end_time", ms(end)))
                            le.append(w)

                            if atom.particles is not None:
                                edge = len(atom.text)
                                edge_l = 0
                                if atom.particle_edge:
                                    edge = atom.particle_edge
                                if atom.particle_edge_l:
                                    edge_l = atom.particle_edge_l
                                rt = ""
                                for i in atom.particles:
                                    rt += i.text
                                r = ET.Element("ruby")
                                r.append(self._tag("text", rt))
                                r.append(
                                    self._tag("start_pos",
                                              "%d" % (len(text) + edge_l)))
                                r.append(
                                    self._tag("end_pos",
                                              "%d" % (len(text) + edge - 1)))
                                ruby.append(r)

                            text += atom.text
                        if idx != (len(line.molecules) - 1):
                            text += " "
                            w[0].text += " "
                        if styles and instance.style == styles[-1]:
                            styles[-1][2] = len(text) - 1
                        else:
                            styles.append(
                                [instance.style, start_pos,
                                 len(text) - 1])

                    for r in ruby:
                        le.append(r)

                    print(text)
                    width = line.max_px - line.min_px
                    cwidth = len(text)
                    for i in text:
                        ew = unicodedata.east_asian_width(i)
                        if ew in ("F", "W", "A"):
                            cwidth += 1

                    if cwidth > 26:
                        print("  ^-- WARNING: Line likely too long")

                for style, start, end in styles:
                    e = ET.Element("color")
                    e.append(
                        self._tag("before_text_color", color(style.colors[0])))
                    e.append(
                        self._tag("after_text_color",
                                  color(style.colors_on[0])))
                    e.append(
                        self._tag("before_shadow_color",
                                  color(style.colors[1])))
                    e.append(
                        self._tag("after_shadow_color",
                                  color(style.colors_on[1])))
                    e.append(
                        self._tag("before_text_no_fill_color",
                                  color(style.colors[0])))
                    e.append(
                        self._tag("after_text_no_fill_color",
                                  color(style.colors_on[0])))
                    e.append(
                        self._tag("before_shadow_no_fill_color",
                                  color(style.colors[1])))
                    e.append(
                        self._tag("after_shadow_no_fill_color",
                                  color(style.colors_on[1])))
                    e.append(self._tag("start_pos", "%d" % start))
                    e.append(self._tag("end_pos", "%d" % end))
                    e.append(
                        self._tag(
                            "no_fill",
                            "1" if style.colors == style.colors_on else "0"))
                    le.append(e)

                e = ET.Element("duet")
                e.append(self._tag("mark", "0"))
                e.append(self._tag("start_pos", "0"))
                e.append(self._tag("end_pos", "%d" % (len(text) - 1)))
                le.append(e)

                e = ET.Element("offset")
                w = 720
                margin = 54
                offset = margin + (w * (1 - width) - 2 * margin) * align
                if offset < 0 or offset + w * width > w - margin:
                    print("  ^-- WARNING: Line too wide")
                # 0 = default
                # 1 = offset from default
                # 2 = abs left side
                e.append(self._tag("type", "2"))
                e.append(self._tag("auto_pos", "0"))
                e.append(self._tag("offset", "%d" % round(offset)))
                le.append(e)

                pe.append(le)

            telop.append(pe)

        self.root.remove(telop)
        self.root.append(telop)

        telop_edit_setting = ET.XML("""
            <telop_edit_setting>
                <music_volume>50</music_volume>
                <vocal_volume>50</vocal_volume>
            </telop_edit_setting>
        """.replace("\n", "").replace(" ", ""))
        self.root.append(telop_edit_setting)