Skip to content

Commit

Permalink
Merge pull request lhartikk#84 from DrDub/master
Browse files Browse the repository at this point in the history
Added generated audio for ArnoldC scripts using FreeTTS.
  • Loading branch information
lhartikk committed Dec 30, 2014
2 parents 8d2994e + c141cd5 commit 62509d2
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 9 deletions.
14 changes: 12 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ name := "ArnoldC"

version := "0.1"

scalaVersion := "2.10.2"
scalaVersion := "2.11.4"

ideaExcludeFolders += ".idea"

Expand All @@ -16,4 +16,14 @@ libraryDependencies += "asm" % "asm-commons" % "3.3.1"

libraryDependencies += "org.parboiled" %% "parboiled-scala" % "1.1.6"

libraryDependencies += "org.scalatest" % "scalatest_2.10" % "2.0" % "test"
libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.1" % "test"

libraryDependencies ++= Seq(
"javax.speech" % "jsapi" % "1.0",
"org.mobicents.external.freetts" % "cmu_us_kal" % "1.0",
"org.mobicents.external.freetts" % "freetts" % "1.0",
"org.mobicents.external.freetts" % "en_us" % "1.0",
"org.mobicents.external.freetts" % "cmulex" % "1.0"
)

resolvers += "Speech" at "http://maven.it.su.se/it.su.se/maven2"
10 changes: 6 additions & 4 deletions src/main/scala/org/arnoldc/ArnoldC.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package org.arnoldc

import java.io.FileOutputStream
import org.arnoldc.ast.RootNode

object ArnoldC {
def main(args: Array[String]) {
if (args.length < 1) {
println("Usage: ArnoldC [-run] [FileToSourceCode]")
println("Usage: ArnoldC [-run|-declaim] [FileToSourceCode]")
return
}
val filename = getFilNameFromArgs(args)
Expand All @@ -17,13 +18,13 @@ object ArnoldC {
else {
filename
}
val bytecode = a.generate(sourceCode, classFilename)
val (bytecode, root) = a.generate(sourceCode, classFilename)

val out = new FileOutputStream(classFilename + ".class")
out.write(bytecode)
out.close()

processOption(getCommandFromArgs(args), classFilename)
processOption(getCommandFromArgs(args), classFilename, root)

}

Expand All @@ -39,8 +40,9 @@ object ArnoldC {
case _ => throw new RuntimeException("WHAT THE FUCK DID I DO WRONG!")
}

def processOption(command:String, argFunc: => String):Unit = command match {
def processOption(command:String, argFunc: => String, root: RootNode):Unit = command match {
case "-run" => Executor.execute(argFunc)
case "-declaim" => Declaimer.declaim(root, argFunc)
case _ =>
}

Expand Down
6 changes: 4 additions & 2 deletions src/main/scala/org/arnoldc/ArnoldGenerator.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package org.arnoldc

import org.arnoldc.ast.RootNode


class ArnoldGenerator extends ClassLoader {

def generate(arnoldCode: String, filename: String): Array[Byte] = {
def generate(arnoldCode: String, filename: String): (Array[Byte], RootNode) = {
val parser = new ArnoldParser
val rootNode = parser.parse(arnoldCode)
rootNode.generateByteCode(filename)
(rootNode.generateByteCode(filename), rootNode)
}
}
159 changes: 159 additions & 0 deletions src/main/scala/org/arnoldc/Declaimer.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package org.arnoldc

import java.util.Locale
import javax.speech.Central
import javax.speech.synthesis.Synthesizer
import javax.speech.synthesis.SynthesizerModeDesc
import javax.speech.synthesis.Voice
import com.sun.speech.freetts.audio.AudioPlayer
import com.sun.speech.freetts.audio.SingleFileAudioPlayer
import javax.sound.sampled.AudioFileFormat.Type
import org.arnoldc.ast._

object Declaimer {

val p = new ArnoldParser

def declaim(root: RootNode, outputFile: String): Unit = {
SpeechUtils.init("kevin16", outputFile)
declaim(root)
SpeechUtils.terminate()
}

def say(text: String) = SpeechUtils.doSpeak(text + "!\n")

def declaim(node: AstNode): Unit = node match {
case RootNode(methods) => methods.map(m => declaim(m))
case MainMethodNode(stmts) =>
say(p.BeginMain)
stmts foreach declaim
say(p.EndMain)
case MethodNode(name, args, ret, stmts) =>
say(s"${p.DeclareMethod} $name")
args.foreach(a => say(s"${p.MethodArguments} ${a.variableName}"))
if (ret) say(p.NonVoidMethod);
stmts.map(s => declaim(s))
say(p.EndMethodDeclaration)

case AssignVariableNode(name, expr) =>
say(s"${p.AssignVariable} $name")
say(p.SetValue)
declaim(expr)
say(p.EndAssignVariable)
case PrintNode(what) =>
say(p.Print)
declaim(what)
case DeclareIntNode(name, value) =>
say(s"${p.DeclareInt} $name")
say(s"${p.SetInitialValue} $value")
case ConditionNode(condition, ifStmts, elseStmts) =>
say(p.If)
declaim(condition)
ifStmts foreach declaim
if (elseStmts.nonEmpty) {
say(p.Else)
elseStmts foreach declaim
}
say(p.EndIf)
case WhileNode(condition, stmts) =>
say(p.While)
declaim(condition)
stmts foreach declaim
say(p.EndWhile)
case CallMethodNode(variable, name, args) =>
if (variable.nonEmpty) {
say(s"${p.AssignVariableFromMethodCall} $variable")
}
say(s"${p.CallMethod} $name")
args foreach declaim
case CallReadMethodNode(variable) =>
say(s"${p.Read} $variable")
case ReturnNode(expr) =>
say(p.Return)
expr.map { x => declaim(x) }

case AndNode(expr1, expr2) =>
declaim(expr1)
say(p.And)
declaim(expr2)
case OrNode(expr1, expr2) =>
declaim(expr1)
say(p.Or)
declaim(expr2)
case PlusExpressionNode(expr1, expr2) =>
declaim(expr1)
say(p.PlusOperator)
declaim(expr2)
case MinusExpressionNode(expr1, expr2) =>
declaim(expr1)
say(p.MinusOperator)
declaim(expr2)
case DivisionExpressionNode(expr1, expr2) =>
declaim(expr1)
say(p.DivisionOperator)
declaim(expr2)
case MultiplicationExpressionNode(expr1, expr2) =>
declaim(expr1)
say(p.MultiplicationOperator)
declaim(expr2)
case ModuloExpressionNode(expr1, expr2) =>
declaim(expr1)
say(p.Modulo)
declaim(expr2)
case GreaterThanNode(expr1, expr2) =>
declaim(expr1)
say(p.GreaterThan)
declaim(expr2)
case EqualToNode(expr1, expr2) =>
declaim(expr1)
say(p.EqualTo)
declaim(expr2)

case NumberNode(num) => say(num.toString)
case StringNode(str) => say(str)
case VariableNode(name) => say(name)

case other => say(s"${p.ParseError} $other")
}

}

object SpeechUtils {
System.setProperty("freetts.voices",
"com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory")

val desc = new SynthesizerModeDesc(Locale.US)

Central.registerEngineCentral("com.sun.speech.freetts.jsapi.FreeTTSEngineCentral")

val synthesizer = Central.createSynthesizer(desc)
synthesizer.allocate()
synthesizer.resume()

val smd = synthesizer.getEngineModeDesc().asInstanceOf[SynthesizerModeDesc]
val voices = smd.getVoices()

var voice: Voice = null

def init(voiceName: String, outputFile: String) {
for (v <- voices) {
if (v.getName().equals(voiceName)) {
voice = v
val audioPlayer = new SingleFileAudioPlayer(outputFile, Type.WAVE);
voice.asInstanceOf[com.sun.speech.freetts.jsapi.FreeTTSVoice].getVoice.setAudioPlayer(audioPlayer)
synthesizer.getSynthesizerProperties().setVoice(voice);
return
}
}
}

def terminate() = {
synthesizer.deallocate()
}

def doSpeak(speakText: String) {
//println(speakText)
synthesizer.speakPlainText(speakText, null);
synthesizer.waitEngineState(Synthesizer.QUEUE_EMPTY);
}
}
2 changes: 1 addition & 1 deletion src/test/scala/org/arnoldc/ArnoldGeneratorTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ abstract class ArnoldGeneratorTest extends FlatSpec with Matchers {
var className = "Hello"

def getOutput(arnoldCode: String): String = {
val bytecode = arnoldGenerator.generate(arnoldCode, className)
val (bytecode, root) = arnoldGenerator.generate(arnoldCode, className)
byteCodeExecutor.getOutput(bytecode, className)
}

Expand Down

0 comments on commit 62509d2

Please sign in to comment.