Example #1
0
def writeLyrics(fileName, inputDir, outputDir, offset=0, newBPM=None):
    fullInputFileDirectory = "./{0}/{1}".format(inputDir, fileName)
    fullOutputFileDirectory = "./{0}/{1}.json".format(
        outputDir, fileName[:-4])  # Alternatively, do songTitle.
    lyricOverTime = []
    karFile = mf.midifile()

    try:
        karFile.load_file(fullInputFileDirectory)
    except IndexError:  #If, for some god-forsaken reason, this doesnt work, Then catch the errors that we are sick of seeing.
        print("Didn't Write '{}'".format(fileName))
    except UnboundLocalError:
        print("Didn't Write '{}'".format(fileName))
    syllables = karFile.karsyl
    times = karFile.kartimes
    bpms = karFile.bpm
    oldBPM = bpms[0][0]

    if offset is None:
        offset = 0
    if newBPM is None or newBPM is 0:
        newBPM = oldBPM
    for i, time in enumerate(times):
        lyric = syllables[i]
        while lyric.find('\xb4') != -1:
            index = lyric.find('\xb4')
            lyric = lyric[:index] + "\'" + lyric[index + 1:]
            print("Found Lyric:", index)
        print("LYRIC:", lyric)
        # lyric = lyric.encode(ISO-8859-1')
        stamp = TimeStampEvent(time, lyric)
        stamp.shiftTime(offset)
        stamp.normalizeBPM(oldBPM, newBPM)
        lyricOverTime.append(stamp.__dict__)
    print(lyricOverTime)
    #Convert it to a json String
    jsonTimeStamps = json.dumps(lyricOverTime)

    #Create a new file for it at the full output directory
    timeStampFile = open(fullOutputFileDirectory, "w")

    if jsonTimeStamps != '[]':  #Only write it if it has content.
        print("Wrote {}".format(fileName))
        timeStampFile.write(jsonTimeStamps)
Example #2
0
#!/usr/bin/env python

# example1.py is an extremely simple text-based karaoke application that
#  runs on the console. It doesn't play any music, just shows the lyrics. 
# This adds music to example1.py using the power of pygame. 
# Requires: pygame. 

import midifile, time, datetime, sys
import pygame

filename=raw_input('Please enter filename of .mid or .kar file:')
m=midifile.midifile()
m.load_file(filename)

pygame.mixer.init()
pygame.mixer.music.load(filename)
pygame.mixer.music.play(0,0) # Start song at 0 and don't loop
start=datetime.datetime.now()

if not m.karfile:
    print "This is not a karaoke file. I'll just play it"
    while pygame.mixer.music.get_busy():
        time.sleep(1)
    sys.exit(0)


#start=start-datetime.timedelta(0,90) # To start lyrics at a later point
dt=0.
while pygame.mixer.music.get_busy():
    dt=(datetime.datetime.now()-start).total_seconds()
    m.update_karaoke(dt)
Example #3
0
    def __init__(self, filename, justForTheLyrics=False):
        self.filename = filename
        self.songname = os.path.basename(filename).replace(".kar", "")
        self.MP3S_DIR = "./mp3s/" + self.songname + "/"
        self.WAVS_DIR = self.MP3S_DIR.replace("mp3", "wav")
        self.lyrics = None
        self.tonedSyls = None
        self.tonedWords = None
        self.firstNoteTime = None
        self.midi = midifile.midifile()
        self.midi.load_file(filename)
        self.FNULL = open(os.devnull, 'w')

        # some initial clean up
        karsyl = list(self.midi.karsyl)
        kartimes = list(self.midi.kartimes)
        for (i, s) in enumerate(karsyl):
            s = s.replace('/', ' ')
            s = s.replace('\\', ' ')
            s = s.replace('_', ' ')
            s = s.replace('\"', '')
            s = s.replace('\'', '')
            s = s.replace(',', '')
            s = s.replace('.', '')
            s = s.replace('!', '')
            s = s.replace('?', '')
            karsyl[i] = s

        # get syllables and times
        syls = [(s, t) for (s, t) in zip(karsyl, kartimes) if s != '']

        # this is a long string with the lyrics
        self.lyrics = ""
        for (s, t) in syls:
            self.lyrics += s
        self.lyrics = self.lyrics.strip()
        print self.lyrics.decode('iso-8859-1')

        if (justForTheLyrics):
            return

        # only return non-empty syllables
        syls = [(s.decode('iso-8859-1').lower().encode('iso-8859-1'), t)
                for (s, t) in syls if s != '' and s != ' ']

        noteTrack = None
        # figure out which track has notes for the lyrics
        minDiff = -1
        candidatesForRemoval = []
        toneTempoList = []
        toneMedian = -1
        toneMax = -1
        firstNoteTime = -1
        for n in range(self.midi.ntracks):
            thisTrack = [v for v in self.midi.notes if v[4] == n]
            if (len(thisTrack) > 0):
                candidatesForRemoval.append(n)

                # deal with percussion tracks with lots of "notes"
                if len(thisTrack) < 2 * len(syls):
                    currentSum = 0
                    numberOfSums = len(syls)
                    currentToneList = []
                    currentToneMin = -1
                    currentToneMax = -1
                    thisTracksFirstNoteTime = thisTrack[0][5]

                    for (s, t) in syls:
                        minDistance = -1
                        minDistanceTone = -1
                        minDistanceTempo = -1
                        for (i, v) in enumerate(thisTrack):
                            if (minDistance
                                    == -1) or abs(t - v[5]) < minDistance:
                                minDistance = abs(t - v[5])
                                minDistanceTone = v[0]
                                minDistanceTempo = 0

                                ii = i
                                while (minDistanceTempo
                                       == 0) and (ii + 1 < len(thisTrack)):
                                    minDistanceTempo = thisTrack[ii][5] - v[5]
                                    ii += 1
                                if (minDistanceTempo == 0):
                                    ii = max(1, i)
                                    minDistanceTempo = thisTrack[ii][
                                        5] - thisTrack[ii - 1][5]

                        currentSum = currentSum + minDistance * minDistance
                        currentToneList.append(
                            (minDistanceTone, minDistanceTempo))
                        if (currentToneMin
                                == -1) or (minDistanceTone < currentToneMin):
                            currentToneMin = minDistanceTone
                        if (currentToneMax
                                == -1) or (minDistanceTone > currentToneMax):
                            currentToneMax = minDistanceTone

                    if (minDiff
                            == -1) or (currentSum / numberOfSums < minDiff):
                        minDiff = currentSum / numberOfSums
                        noteTrack = n
                        toneTempoList = currentToneList
                        firstNoteTime = thisTracksFirstNoteTime
                        toneMedian = int(currentToneMin +
                                         (currentToneMax - currentToneMin) / 2)
                        toneMax = currentToneMax
                        toneSum = sum(
                            [tone for (tone, tempo) in toneTempoList])
                        print "tone(max, med, avg): %s %s %s" % (
                            currentToneMax, toneMedian,
                            toneSum / len(toneTempoList))

        if len(toneTempoList) > len(syls):
            toneTempoList = toneTempoList[0:len(syls)]
        if len(toneTempoList) < len(syls):
            syls = syls[0:len(toneTempoList)]

        if len(toneTempoList) != len(syls):
            print "tone list length doesn't equal syllable list length"
            sys.exit(0)

        ## zip tone array into syls
        ##     this keeps track of tones relative to median
        self.tonedSyls = [(s.strip(), t, p - toneMedian, d)
                          for ((s, t), (p, d)) in zip(syls, toneTempoList)]
        self.firstNoteTime = firstNoteTime

        ## write out wav from stripped midi
        if not os.path.exists(self.WAVS_DIR):
            os.makedirs(self.WAVS_DIR)

        tracks2remove = [
            t for t in candidatesForRemoval
            if t != noteTrack and t != self.midi.kartrack
        ]
        outFileKar = self.filename.replace(".kar", "__.kar")
        self.midi.write_file(self.filename, outFileKar, tracks2remove, None,
                             noteTrack)
        outFileWav = "%s/00.%s.wav" % (self.WAVS_DIR, self.songname)
        midiParams = "-A 100 %s -OwM -o %s" % (outFileKar, outFileWav)
        subprocess.call('timidity ' + midiParams,
                        shell=True,
                        stdout=self.FNULL,
                        stderr=subprocess.STDOUT)
        os.remove(outFileKar)

        if (toneMax > 70):
            pitchParam = 70 - toneMax
            inFileWav = "%s/xx.%s.wav" % (self.WAVS_DIR, self.songname)
            subprocess.call('mv %s %s' % (outFileWav, inFileWav),
                            shell='True',
                            stdout=self.FNULL,
                            stderr=subprocess.STDOUT)

            stParams = "%s %s -pitch=%s" % (inFileWav, outFileWav, pitchParam)
            subprocess.call('soundstretch ' + stParams,
                            shell='True',
                            stdout=self.FNULL,
                            stderr=subprocess.STDOUT)
            subprocess.call('rm %s' % (inFileWav),
                            shell='True',
                            stdout=self.FNULL,
                            stderr=subprocess.STDOUT)

        ## fix case where syllable has multiple syllables
        ultimateSyls = []
        for (s, t, p, d) in self.tonedSyls:
            for w in s.split():
                ultimateSyls.append((w, t, p, d))

        # get tuple of (word, (trigger-times), (pitches), duration)
        words = []
        sylIndex = 0
        for w in self.lyrics.decode('iso-8859-1').lower().encode(
                'iso-8859-1').split():
            (s, t, p, d) = ultimateSyls[sylIndex]
            fromSyls = s
            tt = [t]
            pp = [p]
            dd = d
            sylIndex += 1
            while (fromSyls != w):
                (s, t, p, d) = ultimateSyls[sylIndex]
                fromSyls += s
                tt.append(t)
                pp.append(p)
                dd += d
                sylIndex += 1
            words.append((w, tt, pp, dd))

        ## put words with same start time back together
        ultimateWords = []
        i = 0
        while (i < len(words)):
            currentWord = words[i]
            ii = i + 1
            while (ii < len(words)) and (words[i][1][0] == words[ii][1][0]):
                currentWord = words[i] if (
                    words[i][3] > words[ii][3]) else words[ii]
                ii += 1
            i = ii
            ultimateWords.append(currentWord)

        self.tonedWords = ultimateWords
import os, re, sys
import midifile

OUT_KAR_DIR = "./out-kars/"
OUT_LYRICS_DIR = "./out-lyrics/"

## make sure we're getting a kar file
inFileKar = ''
if len(sys.argv) > 1 and sys.argv[1].endswith(".kar"):
    inFileKar = sys.argv[1]
else:
    print "Please provide a .kar karaoke file"
    sys.exit(0)

## read it and make sure it's a valid kar file
myKar = midifile.midifile()
myKar.load_file(inFileKar)
if not myKar.karfile:
    print "This is not a valid karaoke file"
    sys.exit(0)

## get filename from file location
filename = os.path.basename(inFileKar)

## create directory for decomposed kar files
if not os.path.exists(OUT_KAR_DIR):
    os.makedirs(OUT_KAR_DIR)

## determine which tracks are being used for notes
candidateTracks = {}
for v in myKar.notes: