{"id":1072,"date":"2016-09-30T18:00:36","date_gmt":"2016-09-30T16:00:36","guid":{"rendered":"\/\/www.mcgill.org.za\/stuff\/?p=1072"},"modified":"2016-09-30T20:17:38","modified_gmt":"2016-09-30T18:17:38","slug":"illsong","status":"publish","type":"post","link":"https:\/\/www.mcgill.org.za\/stuff\/archives\/1072","title":{"rendered":"Illsong"},"content":{"rendered":"<p>Being distressed at the prospect of singing a Hillsong song, I collected all the lyrics of 100 or so Hillsong songs, and put them through a Markov chain generator, to generate new songs in the style of the originals.\u00a0 The parameters used are:<\/p>\n<ul>\n<li>order: 10 &#8211; this is the length of memory<\/li>\n<li>prior: 0.0001 &#8211; the bias towards using something unknown<\/li>\n<li>corpus: the complete lyrics of each song make up the sample data, ie. each song is represented as a single string.\u00a0 The results then are songs comprised of multiple lines, as a single string.<\/li>\n<\/ul>\n<p>The results are about as coherent and approximately as Biblically sound as bulk of the songs that Hillsong writes.\u00a0 Have I mentioned that I find the lyrics repetitive and incoherent?<\/p>\n<p>Here are three selections. Notice the odd spelling mistake &#8211; that&#8217;s the Markov thing randomly choosing to make an error.\u00a0 I made up titles for fun:<\/p>\n<h2>No end, this was not a new thing<\/h2>\n<blockquote><p>There&#8217;s no end to Your embrace<br \/>\nLight of the world<br \/>\nLet the poor say, &#8220;I am rich&#8221;<br \/>\nLet the poke the Earth, let us sing<br \/>\nGod, our hope is Yahweh, Yahweh<br \/>\nForever You will never fail<br \/>\nYour name shout in all the earth<br \/>\nWill fade away<br \/>\nStill my soul<br \/>\nMy heart within the darkness<br \/>\nGlory pierced the night sky<br \/>\nYou give me breath and all I found was You<br \/>\nMy God, I&#8217;ll only ever give You my heart<br \/>\nDistant shores and the end<br \/>\nThe promise out<br \/>\nThis was not a new thing<br \/>\nUntil itSaviour, He can move the mountains with a whisper<br \/>\nAnd You calm my soul<br \/>\nOh, now save<br \/>\nOur God is great and mighty<br \/>\nGod in three persons, blessed Trinity<\/p><\/blockquote>\n<h2>In the highest praise at the sound of faith<\/h2>\n<blockquote><p>To the Lamb that was slain<br \/>\nHosanna, Hosanna<br \/>\nHosanna in the highest praise<br \/>\nWhat can separate us<br \/>\nNothing can separate me now<br \/>\nYou taught a way, You made a way<br \/>\nWhen You call, I won&#8217;t hide it, I won&#8217;t refuse<br \/>\nEach new day again I&#8217;ll choose<br \/>\nThere is none like You<br \/>\nThere is no one like You, God<br \/>\nMountains bow down and the seas will roar<br \/>\nAt the sound of faith<br \/>\nand the words to express the way of the Lord<br \/>\nEternity&#8217;s King<br \/>\nIs coming again<br \/>\nThough all of the universe is at Your feet<br \/>\nHide me now in the shadow of Your word, Your name<br \/>\n&#8220;I live to know You<br \/>\nI live to know You<br \/>\nLet go and throw my life has changed<br \/>\nWhen You took a crown of thorns<br \/>\nAnd Your blood was spilled<br \/>\nFor my ransom<br \/>\nEverything I have, I give You praise in all of the earth rejoice<br \/>\nLet all the heavens<br \/>\nFor You are holy, You are holy, You alone<br \/>\nAwake my soul the reason why I sing<br \/>\nAll around the words to express<br \/>\nthere&#8217;s nothing like<br \/>\nYour love You always<\/p><\/blockquote>\n<h2>Nothing that&#8217;s true<\/h2>\n<blockquote><p>For all Your sons and daughters<br \/>\nWho are walking in the east, beyond the heavens<br \/>\nAnd Your love transforms my soul, He is the Lord with all my hope is in You<br \/>\nJesus Christ the Savior is born<br \/>\nHe shall become a wonderful counselor, everlasting Lord<br \/>\nLate in time, beholding Your beauty<br \/>\nAnd in the palm of Your hands I belong, I&#8217;m a living stone<br \/>\nIn this house I will grow<br \/>\nThere is nothing that&#8217;s true<\/p><\/blockquote>\n<p>The script:<\/p>\n<pre>#! \/usr\/bin\/python\r\n\r\nfrom __future__ import division\r\nimport random\r\n\r\n\r\nclass Categorical(object):\r\n\r\n    def __init__(self, support, prior):\r\n        self.counts = {x: prior for x in support}\r\n        self.total = sum(self.counts.itervalues())\r\n\r\n    def observe(self, event, count=1):\r\n        self.counts[event] += count\r\n        self.total += count\r\n\r\n    def sample(self, dice=random):\r\n        sample = dice.uniform(0, self.total)\r\n        for event, count in self.counts.iteritems():\r\n            if sample &lt;= count: return event sample -= count def __getitem__(self, event): return self.counts[event] \/ self.total class MarkovModel(object): def __init__(self, support, order, prior, boundary_symbol=None): self.support = set(support) self.support.add(boundary_symbol) self.order = order self.prior = prior self.boundary = boundary_symbol self.prefix = [self.boundary] * self.order self.postfix = [self.boundary] self.counts = {} def _categorical(self, context): if context not in self.counts: self.counts[context] = Categorical(self.support, self.prior) return self.counts[context] def _backoff(self, context): context = tuple(context) if len(context) &gt; self.order:\r\n            context = context[-self.order:]\r\n        elif len(context) &lt; self.order: context = (self.boundary,) * (self.order - len(context)) + context while context not in self.counts and len(context) &gt; 0:\r\n            context = context[1:]\r\n        return context\r\n\r\n    def observe(self, sequence, count=1):\r\n        sequence = self.prefix + list(sequence) + self.postfix\r\n        for i in range(self.order, len(sequence)):\r\n            context = tuple(sequence[i - self.order:i])\r\n            event = sequence[i]\r\n            for j in range(len(context) + 1):\r\n                self._categorical(context[j:]).observe(event, count)\r\n\r\n    def sample(self, context):\r\n        context = self._backoff(context)\r\n        return self._categorical(context).sample()\r\n\r\n    def generate(self):\r\n        sequence = [self.sample(self.prefix)]\r\n        while sequence[-1] != self.boundary:\r\n            sequence.append(self.sample(sequence))\r\n        return sequence[:-1]\r\n\r\n    def __getitem__(self, condition):\r\n        event = condition.start\r\n        context = self._backoff(condition.stop)\r\n        return self._categorial(context)[event]\r\n\r\nclass NameGenerator(object):\r\n    def __init__(self, name_file, order=3, prior=.001):\r\n        self.names = set()\r\n        support = set()\r\n        for name in name_file:\r\n            name = name.strip()\r\n            if len(name) &gt; 0:\r\n                self.names.add(name)\r\n                support.update(name)\r\n        self.model = MarkovModel(support, order, prior)\r\n        for name in self.names:\r\n            self.model.observe(name)\r\n\r\n    def generate(self):\r\n        while True:\r\n            word = ''.join(self.model.generate())\r\n            return word\r\n\r\ndef readsongs(fd):\r\n    o=[]\r\n    for line in fd:\r\n        o.append(line)\r\n        if line.strip()=='':\r\n            yield ''.join(o)\r\n            o=[]\r\n    if len(o):\r\n        yield ''.join(o)\r\n\r\nif __name__==\"__main__\":\r\n    import os,sys\r\n    fd=open(sys.argv[1],'r')\r\n    \r\n    ng=NameGenerator(readsongs(fd), order=10,prior=0.0001)\r\n    while True:\r\n        r= ng.generate()\r\n        if len(r)<\/pre>\n<p>You give that code a file with all the lyrics of your song (delimited by a blank line) and it will spit out a new Illsong &#8211; maybe a better one.\u00a0 WordPress doesn&#8217;t like to publish files (what&#8217;s with that) so you&#8217;ll have to get your own illsong archive to see the wonderful results.\u00a0 The code, by the way, is not my own &#8230; I can&#8217;t figure out where I plagiarised it from.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Being distressed at the prospect of singing a Hillsong song, I collected all the lyrics of 100 or so Hillsong songs, and put them through a Markov chain generator, to generate new songs in the style of the originals.\u00a0 The &hellip; <a href=\"https:\/\/www.mcgill.org.za\/stuff\/archives\/1072\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[25,203,17,30,190],"class_list":["post-1072","post","type-post","status-publish","format-standard","hentry","category-stuff","tag-code","tag-markov","tag-rants","tag-songs","tag-stuff"],"_links":{"self":[{"href":"https:\/\/www.mcgill.org.za\/stuff\/wp-json\/wp\/v2\/posts\/1072","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mcgill.org.za\/stuff\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mcgill.org.za\/stuff\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mcgill.org.za\/stuff\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mcgill.org.za\/stuff\/wp-json\/wp\/v2\/comments?post=1072"}],"version-history":[{"count":8,"href":"https:\/\/www.mcgill.org.za\/stuff\/wp-json\/wp\/v2\/posts\/1072\/revisions"}],"predecessor-version":[{"id":1080,"href":"https:\/\/www.mcgill.org.za\/stuff\/wp-json\/wp\/v2\/posts\/1072\/revisions\/1080"}],"wp:attachment":[{"href":"https:\/\/www.mcgill.org.za\/stuff\/wp-json\/wp\/v2\/media?parent=1072"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mcgill.org.za\/stuff\/wp-json\/wp\/v2\/categories?post=1072"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mcgill.org.za\/stuff\/wp-json\/wp\/v2\/tags?post=1072"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}