├── .gitignore ├── project ├── build.properties └── plugins.sbt ├── version.sbt ├── src └── main │ ├── resources │ ├── Pop.aiff │ ├── Basso.aiff │ ├── Blow.aiff │ ├── Frog.aiff │ ├── Funk.aiff │ ├── Glass.aiff │ ├── Hero.aiff │ ├── Morse.aiff │ ├── Ping.aiff │ ├── Purr.aiff │ ├── Tink.aiff │ ├── Bottle.aiff │ ├── Sosumi.aiff │ └── Submarine.aiff │ └── scala │ └── com │ └── orrsella │ └── sbtsound │ └── SbtSound.scala ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | target -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.1.4 2 | -------------------------------------------------------------------------------- /version.sbt: -------------------------------------------------------------------------------- 1 | version in ThisBuild := "1.0.7-SNAPSHOT" 2 | -------------------------------------------------------------------------------- /src/main/resources/Pop.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orrsella/sbt-sound/HEAD/src/main/resources/Pop.aiff -------------------------------------------------------------------------------- /src/main/resources/Basso.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orrsella/sbt-sound/HEAD/src/main/resources/Basso.aiff -------------------------------------------------------------------------------- /src/main/resources/Blow.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orrsella/sbt-sound/HEAD/src/main/resources/Blow.aiff -------------------------------------------------------------------------------- /src/main/resources/Frog.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orrsella/sbt-sound/HEAD/src/main/resources/Frog.aiff -------------------------------------------------------------------------------- /src/main/resources/Funk.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orrsella/sbt-sound/HEAD/src/main/resources/Funk.aiff -------------------------------------------------------------------------------- /src/main/resources/Glass.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orrsella/sbt-sound/HEAD/src/main/resources/Glass.aiff -------------------------------------------------------------------------------- /src/main/resources/Hero.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orrsella/sbt-sound/HEAD/src/main/resources/Hero.aiff -------------------------------------------------------------------------------- /src/main/resources/Morse.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orrsella/sbt-sound/HEAD/src/main/resources/Morse.aiff -------------------------------------------------------------------------------- /src/main/resources/Ping.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orrsella/sbt-sound/HEAD/src/main/resources/Ping.aiff -------------------------------------------------------------------------------- /src/main/resources/Purr.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orrsella/sbt-sound/HEAD/src/main/resources/Purr.aiff -------------------------------------------------------------------------------- /src/main/resources/Tink.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orrsella/sbt-sound/HEAD/src/main/resources/Tink.aiff -------------------------------------------------------------------------------- /src/main/resources/Bottle.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orrsella/sbt-sound/HEAD/src/main/resources/Bottle.aiff -------------------------------------------------------------------------------- /src/main/resources/Sosumi.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orrsella/sbt-sound/HEAD/src/main/resources/Sosumi.aiff -------------------------------------------------------------------------------- /src/main/resources/Submarine.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orrsella/sbt-sound/HEAD/src/main/resources/Submarine.aiff -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.8") 2 | 3 | addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.1") 4 | 5 | addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "2.3") 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This software is licensed under the Apache 2 license, quoted below. 2 | 3 | Copyright (c) 2013 Orr Sella 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. -------------------------------------------------------------------------------- /src/main/scala/com/orrsella/sbtsound/SbtSound.scala: -------------------------------------------------------------------------------- 1 | package com.orrsella.sbtsound 2 | 3 | import java.io.{InputStream, FileInputStream} 4 | import sbt._ 5 | import sun.audio.{AudioStream, AudioPlayer} 6 | 7 | object SbtSound extends AutoPlugin { 8 | abstract class Sound { 9 | def play() 10 | def play(input: InputStream) { 11 | AudioPlayer.player.start(new AudioStream(input)) 12 | } 13 | } 14 | 15 | case class FileSound(path: String) extends Sound { 16 | def play() { 17 | play(new FileInputStream(path)) 18 | } 19 | } 20 | 21 | case class ResourceSound(res: String) extends Sound { 22 | def play() { 23 | play(getClass.getResourceAsStream(res)) 24 | } 25 | } 26 | 27 | object Sounds { 28 | object None extends FileSound("") 29 | object Basso extends ResourceSound("/Basso.aiff") 30 | object Blow extends ResourceSound("/Blow.aiff") 31 | object Bottle extends ResourceSound("/Bottle.aiff") 32 | object Frog extends ResourceSound("/Frog.aiff") 33 | object Funk extends ResourceSound("/Funk.aiff") 34 | object Glass extends ResourceSound("/Glass.aiff") 35 | object Hero extends ResourceSound("/Hero.aiff") 36 | object Morse extends ResourceSound("/Morse.aiff") 37 | object Ping extends ResourceSound("/Ping.aiff") 38 | object Pop extends ResourceSound("/Pop.aiff") 39 | object Purr extends ResourceSound("/Purr.aiff") 40 | object Sosumi extends ResourceSound("/Sosumi.aiff") 41 | object Submarine extends ResourceSound("/Submarine.aiff") 42 | object Tink extends ResourceSound("/Tink.aiff") 43 | } 44 | 45 | object sound { 46 | val default = Sounds.Glass 47 | 48 | def play[T](t: TaskKey[T]): Setting[Task[T]] = play(t, default, default) 49 | def play[T](t: TaskKey[T], s: String): Setting[Task[T]] = play(t, FileSound(s), FileSound(s)) 50 | def play[T](t: TaskKey[T], s: Sound): Setting[Task[T]] = play(t, s, s) 51 | def play[T](t: TaskKey[T], suc: String, fail: Sound): Setting[Task[T]] = play(t, FileSound(suc), fail) 52 | def play[T](t: TaskKey[T], suc: Sound, fail: String): Setting[Task[T]] = play(t, suc, FileSound(fail)) 53 | def play[T](t: TaskKey[T], suc: String, fail: String): Setting[Task[T]] = play(t, FileSound(suc), FileSound(fail)) 54 | 55 | def play[T](t: TaskKey[T], suc: Sound, fail: Sound): Setting[Task[T]] = { 56 | t := { 57 | t.result.value match { 58 | case Inc(inc: Incomplete) => 59 | if (fail != Sounds.None) fail.play() 60 | throw inc 61 | case Value(value) => 62 | if (suc != Sounds.None) suc.play() 63 | value 64 | } 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sbt-sound 2 | 3 | An [sbt](http://www.scala-sbt.org/) (Simple Build Tool) plugin for adding sounds to sbt's task completions. 4 | 5 | This plugin allows you to associate sounds with successful and/or failed task completions, giving you audio feedback. Any `TaskKey` can have a sound association. This is especially useful for: 6 | 7 | * Long build times 8 | * A failing `~compile` that is running in the background/behind other windows 9 | * A failing `~test` 10 | * Drawing your attention to any specific task outcome 11 | 12 | The reason I wrote this plugin is that I usually code with a running sbt `~compile` in the background, and would like to know asap when something breaks. I code in [Sublime Text](http://www.sublimetext.com/) (see [my plugin for it](https://github.com/orrsella/sbt-sublime)), and when I'm not connected to an external monitor I have sbt in the background, periodically checking it to see everything's fine. This plugin solves this problem for me, only drawing my attention when the build breaks. I think others could find this plugin useful in other ways as well. 13 | 14 | ## Add Plugin 15 | 16 | To add sbt-sound functionality to your project add the following to your `project/plugins.sbt` file: 17 | 18 | ```scala 19 | addSbtPlugin("com.orrsella" % "sbt-sound" % "1.0.6") 20 | 21 | // For sbt 0.12.x, 0.13.x: 22 | addSbtPlugin("com.orrsella" % "sbt-sound" % "1.0.4") 23 | ``` 24 | 25 | ## Usage 26 | 27 | ### Sounds 28 | 29 | The sbt-sound jar comes pre-loaded with 14 sounds (shamelessly copied from Mountain Lion's sounds folder, hope I won't get in trouble for this): 30 | 31 | * Basso 32 | * Blow 33 | * Bottle 34 | * Frog 35 | * Funk 36 | * Glass 37 | * Hero 38 | * Morse 39 | * Ping 40 | * Pop 41 | * Purr 42 | * Sosumi 43 | * Submarine 44 | * Tink 45 | 46 | You can also specify any `.wav` or `.aiff` file on your local machine (maybe other formats work as well, these are the ones I tested with). 47 | 48 | ### Configuration 49 | 50 | #### build.sbt 51 | 52 | After enabling the plugin, you can configure it by adding any of the following to `build.sbt`: 53 | 54 | ```scala 55 | import SbtSound._ 56 | 57 | sound.play(compile in Compile, Sounds.Basso) // play the 'Basso' sound whenever compile completes (successful or not) 58 | 59 | sound.play(compile in Compile, Sounds.None, Sounds.Pop) // play the 'Pop' sound only when compile fails 60 | 61 | sound.play(test in Test, Sounds.Purr, "/Users/me/Sounds/my-sound.wav") // play 'Purr' when test completes successfully 62 | // or the wav file 'my-sound' when it fails 63 | ``` 64 | 65 | You can configure any sbt `TaskKey` (and as many as you like) in the above way. 66 | 67 | #### Build.scala 68 | 69 | If you're using a `.scala` build file, you can add the following: 70 | 71 | ```scala 72 | import com.orrsella.sbtsound.SbtSound._ 73 | ... 74 | 75 | object MyBuild extends Build { 76 | lazy val main = Project ( 77 | "my-proj", 78 | file("."), 79 | settings = 80 | Defaults.defaultSettings ++ 81 | ... ++ 82 | sound.play(installDevice in AndroidKeys.Android, "/Users/mark/Documents/Quatsch/Hoo.wav") 83 | ) 84 | } 85 | ``` 86 | 87 | Above example curtsey of [@i-am-the-slime](https://github.com/i-am-the-slime) – it alerts when an entire build is complete (using the [sbt android-plugin](https://github.com/jberkel/android-plugin) to also install on the device). Example full project definition can be found [here](https://gist.github.com/i-am-the-slime/fc207e61d50e29fe2837/#comment-852708). 88 | 89 | ### Stacking 90 | 91 | The way sbt-sound works is by adding `task <<= (task) mapR { ... }` to every task's completion. Because the functionality is tucked on every task you configure in `build.sbt`, running tasks that depend on other tasks (and execute them), will cause all sounds in the chain to play. So if, for example, you specify a sound for `compile` and `test`, and when running `test` the code compiles because of the `compile` command, both sounds will play. Take that into consideration when configuration which tasks to play sounds for. The easiest way to avoid this problem is to define sounds for failing actions, which usually don't trigger the following tasks, thus solving this "problem". 92 | 93 | ## Feedback 94 | 95 | Any comments/suggestions? Let me know what you think – I'd love to hear from you. Send pull requests, issues or contact me: [@orrsella](http://twitter.com/orrsella) and [orrsella.com](http://orrsella.com) 96 | 97 | ## License 98 | 99 | This software is licensed under the Apache 2 license, quoted below. 100 | 101 | Copyright (c) 2013 Orr Sella 102 | 103 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 104 | 105 | http://www.apache.org/licenses/LICENSE-2.0 106 | 107 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 108 | --------------------------------------------------------------------------------