content-editing-movie-player 0.38.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (273) hide show
  1. data/.gitmodules +3 -0
  2. data/.rvmrc +1 -0
  3. data/LICENSE.TXT +20 -0
  4. data/README.TXT +225 -0
  5. data/Rakefile +206 -0
  6. data/TODO +740 -0
  7. data/VERSION +1 -0
  8. data/_DO_NOT_RUN_IT_FROM_HERE_DOWNLOAD_THE_RELEASE_ZIP_FROM_SOURCEFORGE_INSTEAD +0 -0
  9. data/bin/sensible-cinema +60 -0
  10. data/bin/sensible-cinema-cli +161 -0
  11. data/business_ideas.txt +21 -0
  12. data/change_log_with_feature_list.txt +952 -0
  13. data/documentation/DOCUMENTATION_README.TXT +44 -0
  14. data/documentation/how_to_get_files_from_dvd.txt +30 -0
  15. data/documentation/is_it_legal_to_copy_dvds.txt +97 -0
  16. data/documentation/troubleshooting.txt +30 -0
  17. data/documentation/upconversion.txt +4 -0
  18. data/experimental_online_player_ocr_readme.txt +45 -0
  19. data/go +1 -0
  20. data/go.bat +2 -0
  21. data/go.sh +1 -0
  22. data/go_ocr_tracker.bat +1 -0
  23. data/goc +1 -0
  24. data/goc.bat +1 -0
  25. data/goc.sh +1 -0
  26. data/gpl-2.0.txt +339 -0
  27. data/gplv3.txt +219 -0
  28. data/history_and_related_works_list.txt +108 -0
  29. data/inventionzy_files/cone.png +0 -0
  30. data/inventionzy_files/md5s.txt +53 -0
  31. data/inventionzy_files/play_with_inserted_scene.bat +8 -0
  32. data/inventionzy_files/play_with_overlay.bat +24 -0
  33. data/inventionzy_files/transcript_mute_vlc.txt +117 -0
  34. data/legal_draft +23 -0
  35. data/lib/add_any_bundled_gems_to_load_path.rb +32 -0
  36. data/lib/auto_window_finder.rb +41 -0
  37. data/lib/blanker.rb +104 -0
  38. data/lib/check_installed_mac.rb +34 -0
  39. data/lib/convert_thirty_fps.rb +20 -0
  40. data/lib/edl_parser.rb +387 -0
  41. data/lib/eight_three.rb +28 -0
  42. data/lib/extract/dumpstream.bat +1 -0
  43. data/lib/extract/get_init.bat +3 -0
  44. data/lib/extract/pause_early.rb +13 -0
  45. data/lib/fake_blanker.rb +35 -0
  46. data/lib/frame_accurate.rb +3 -0
  47. data/lib/gui/base.rb +748 -0
  48. data/lib/gui/create-file.rb +24 -0
  49. data/lib/gui/create.rb +581 -0
  50. data/lib/gui/dependencies.rb +219 -0
  51. data/lib/gui/normal.rb +123 -0
  52. data/lib/gui/upconvert.rb +284 -0
  53. data/lib/keyboard_input.rb +60 -0
  54. data/lib/media_info_parser.rb +27 -0
  55. data/lib/mouse_forever.rb +19 -0
  56. data/lib/movie_hasher.rb +27 -0
  57. data/lib/mplayer_edl.rb +42 -0
  58. data/lib/muter.rb +87 -0
  59. data/lib/ocr.rb +125 -0
  60. data/lib/ocr_seed/netflix_b9.bmp +0 -0
  61. data/lib/overlayer.rb +373 -0
  62. data/lib/screen_tracker.rb +269 -0
  63. data/lib/subtitle_profanity_finder.rb +294 -0
  64. data/lib/vlc_programmer.rb +112 -0
  65. data/lib/zoom_player_max_edl.rb +50 -0
  66. data/never_do +40 -0
  67. data/notes_for_potential_developers.txt +46 -0
  68. data/preamble +17 -0
  69. data/roadmap_possibilities +12 -0
  70. data/spec/arse.srt +41 -0
  71. data/spec/auto_window_finder.spec.rb +65 -0
  72. data/spec/bad_beginning.srt +3778 -0
  73. data/spec/blanker.spec.rb +60 -0
  74. data/spec/common.rb +81 -0
  75. data/spec/convert_image.rb +25 -0
  76. data/spec/deity_end.srt +11 -0
  77. data/spec/dragon.srt +34 -0
  78. data/spec/edl_parser.spec.rb +270 -0
  79. data/spec/frame_accurate.spec.rb +71 -0
  80. data/spec/keyboard_input.spec.rb +73 -0
  81. data/spec/media_info_parser.spec.rb +29 -0
  82. data/spec/mplayer_edl.spec.rb +100 -0
  83. data/spec/muter.spec.rb +50 -0
  84. data/spec/notes +4996 -0
  85. data/spec/ocr.spec.rb +119 -0
  86. data/spec/overlayer.spec.rb +440 -0
  87. data/spec/screen_tracker.spec.rb +318 -0
  88. data/spec/sensible_cinema_gui.spec.rb +452 -0
  89. data/spec/subtitle_profanity_finder.spec.rb +224 -0
  90. data/spec/test_yaml.yml +4 -0
  91. data/spec/tsmuxer.output +33 -0
  92. data/spec/vlc_programmer.spec.rb +124 -0
  93. data/spec/youtube_edl.spec.rb +28 -0
  94. data/spec/zoom_player_max_edl.spec.rb +29 -0
  95. data/template_bats/README_DISTRO.TXT +8 -0
  96. data/template_bats/RUN SENSIBLE CINEMA CLICK HERE WINDOWS.bat +25 -0
  97. data/template_bats/_DO_NOT_RUN_IT_FROM_HERE_DOWNLOAD_THE_RELEASE_ZIP_FROM_SOURCEFORGE_INSTEAD +0 -0
  98. data/template_bats/mac/RUN SENSIBLE CINEMA CLICK HERE.command +5 -0
  99. data/template_bats/mac/advanced--create or edit sensible cinema edit list files.command +3 -0
  100. data/template_bats/mac/advanced--run-upconverting-video-player.command +3 -0
  101. data/template_bats/pc/advanced--create or edit sensible cinema edit list files.bat +2 -0
  102. data/template_bats/pc/advanced--run-upconverting-video-player.bat +2 -0
  103. data/todo.build_library.txt +11 -0
  104. data/todo.inventionzy.txt +162 -0
  105. data/todo.open_edl_list_org.txt +169 -0
  106. data/todo.propaganda +107 -0
  107. data/todo.subtitle +17 -0
  108. data/todo.upconvert +53 -0
  109. data/upconvert.bat +1 -0
  110. data/upconvert_from_screen/go_upscaling.bat +12 -0
  111. data/upconvert_from_screen/go_upscaling_works +0 -0
  112. data/upconvert_from_screen/old/latest2/combine_video.avs +23 -0
  113. data/upconvert_from_screen/old/latest2/go_no_upscaling.bat +1 -0
  114. data/upconvert_from_screen/old/latest2/go_upscaling.bat +12 -0
  115. data/upconvert_from_screen/old/latest2/push2.GRF +0 -0
  116. data/upconvert_from_screen/old/latest2/push3.grf +0 -0
  117. data/upconvert_from_screen/old/latest2/setup_capture_coords.rb +27 -0
  118. data/upconvert_from_screen/old/latest2/setup_directshow_filter_params.rb +29 -0
  119. data/upconvert_from_screen/old/latest2/upconvert_from_screen_me2.avs +19 -0
  120. data/upconvert_from_screen/old/latest_now_possibly_oudated/push2.GRF +0 -0
  121. data/upconvert_from_screen/old/latest_now_possibly_oudated/upconvert_from_screen_me2.avs +18 -0
  122. data/upconvert_from_screen/old/position_window.png +0 -0
  123. data/upconvert_from_screen/old/push_source_desktop.GRF +0 -0
  124. data/upconvert_from_screen/old/record_screen/record.bat +2 -0
  125. data/upconvert_from_screen/old/upconvert_from_screen.avs +21 -0
  126. data/upconvert_from_screen/old/upconvert_from_screen_me.avs +21 -0
  127. data/upconvert_from_screen/old/upconvert_from_screen_me2.avs +3 -0
  128. data/upconvert_from_screen/old/upconvert_from_screen_me_push_source.avs +3 -0
  129. data/upconvert_from_screen/old/uscreen.GRF +0 -0
  130. data/upconvert_from_screen/old/uscreen_me.GRF +0 -0
  131. data/upconvert_from_screen/push3.grf +0 -0
  132. data/upconvert_from_screen/upconvert_from_screen_me2.avs +19 -0
  133. data/vendor/movie-content-editor-read-only/.metadata/.lock +0 -0
  134. data/vendor/movie-content-editor-read-only/.metadata/.mylyn/.tasks.xml.zip +0 -0
  135. data/vendor/movie-content-editor-read-only/.metadata/.mylyn/repositories.xml.zip +0 -0
  136. data/vendor/movie-content-editor-read-only/.metadata/.mylyn/tasks.xml.zip +0 -0
  137. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/history.version +1 -0
  138. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.index +0 -0
  139. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.version +1 -0
  140. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.core.resources/.root/2.tree +0 -0
  141. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources +0 -0
  142. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs +3 -0
  143. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.ui.prefs +14 -0
  144. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.context.core.prefs +3 -0
  145. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs +5 -0
  146. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs +3 -0
  147. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.jdt.core/nonChainingJarsCache +0 -0
  148. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.jdt.core/variablesAndContainers.dat +0 -0
  149. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.jdt.ui/OpenTypeHistory.xml +2 -0
  150. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.jdt.ui/QualifiedTypeNameHistory.xml +2 -0
  151. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml +10 -0
  152. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml +11 -0
  153. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.ui.intro/dialog_settings.xml +4 -0
  154. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml +10 -0
  155. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.ui.workbench/workbench.xml +232 -0
  156. data/vendor/movie-content-editor-read-only/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml +4 -0
  157. data/vendor/movie-content-editor-read-only/.metadata/version.ini +1 -0
  158. data/vendor/movie-content-editor-read-only/.project +17 -0
  159. data/vendor/movie-content-editor-read-only/.pydevproject +11 -0
  160. data/vendor/movie-content-editor-read-only/.settings/org.eclipse.core.resources.prefs +6 -0
  161. data/vendor/movie-content-editor-read-only/SubIt.py +171 -0
  162. data/vendor/movie-content-editor-read-only/VLCMacVideo.py +257 -0
  163. data/vendor/movie-content-editor-read-only/VideoMac.ui +102 -0
  164. data/vendor/movie-content-editor-read-only/badwords.txt +4 -0
  165. data/vendor/movie-content-editor-read-only/blank.srt +4 -0
  166. data/vendor/movie-content-editor-read-only/edit.py +197 -0
  167. data/vendor/movie-content-editor-read-only/mergeCommands.py +73 -0
  168. data/vendor/movie-content-editor-read-only/mute.txt +5 -0
  169. data/vendor/movie-content-editor-read-only/panda.srt +4235 -0
  170. data/vendor/movie-content-editor-read-only/panda_custom.txt +3 -0
  171. data/vendor/movie-content-editor-read-only/panda_edit.srt +4235 -0
  172. data/vendor/movie-content-editor-read-only/subtitle.py +90 -0
  173. data/vendor/movie-content-editor-read-only/vlc.py +5579 -0
  174. data/vendor/movie-content-editor-read-only/vlcwidget.py +154 -0
  175. data/vendor/mplayer_patches/how_to_doze.bat +6 -0
  176. data/vendor/mplayer_patches/port_dir/PortIndex.quick +2 -0
  177. data/vendor/mplayer_patches/port_dir/how_to +20 -0
  178. data/vendor/mplayer_patches/port_dir/multimedia/mplayer-edl/Portfile +285 -0
  179. data/vendor/mplayer_patches/port_dir/multimedia/mplayer-edl/files/configure.x11.patch +20 -0
  180. data/vendor/mplayer_patches/port_dir/multimedia/mplayer-edl/files/llvm-gcc-workaround.patch +11 -0
  181. data/vendor/mplayer_patches/port_dir/multimedia/rdp-projects/Portfile +43 -0
  182. data/vendor/mplayer_patches/port_dir_is_for_mac +0 -0
  183. data/www/content_editor.html +92 -0
  184. data/www/index.html +47 -0
  185. data/www/upconverting_movie_player.html +62 -0
  186. data/www/video reel.jpg +0 -0
  187. data/www/youtube_edl/.htaccess +44 -0
  188. data/www/youtube_edl/control_youtube.rhtml +141 -0
  189. data/www/youtube_edl/dispatch.fcgi +25 -0
  190. data/www/youtube_edl/render_edited.rb +25 -0
  191. data/www/youtube_edl/server_this_dir.rb +6 -0
  192. data/www/youtube_edl/todo +23 -0
  193. data/www/zoomplayer_max.png +0 -0
  194. data/zamples/edit_decision_lists/dvds/Harry Potter 2 chamber of secrets.txt +22 -0
  195. data/zamples/edit_decision_lists/dvds/aa_example_delete_list_that_has_no_cuts_in_it.txt +10 -0
  196. data/zamples/edit_decision_lists/dvds/aladdin.txt +30 -0
  197. data/zamples/edit_decision_lists/dvds/bambi.txt +17 -0
  198. data/zamples/edit_decision_lists/dvds/big_buck_bunny_dvd.txt +23 -0
  199. data/zamples/edit_decision_lists/dvds/bob the builder pets in a pickle.txt +10 -0
  200. data/zamples/edit_decision_lists/dvds/bobs_big_plan.txt +10 -0
  201. data/zamples/edit_decision_lists/dvds/cars_2.txt +26 -0
  202. data/zamples/edit_decision_lists/dvds/cars_disney.txt +40 -0
  203. data/zamples/edit_decision_lists/dvds/condor_man_widescreen.txt +22 -0
  204. data/zamples/edit_decision_lists/dvds/cool runnings.txt +53 -0
  205. data/zamples/edit_decision_lists/dvds/court_jester.txt +24 -0
  206. data/zamples/edit_decision_lists/dvds/edls_being_edited/amazing_grace.txt +49 -0
  207. data/zamples/edit_decision_lists/dvds/edls_being_edited/father_goose.txt +41 -0
  208. data/zamples/edit_decision_lists/dvds/edls_being_edited/harry_potter_and_the_goblet_of_fire.txt +45 -0
  209. data/zamples/edit_decision_lists/dvds/edls_being_edited/hugo.txt +31 -0
  210. data/zamples/edit_decision_lists/dvds/edls_being_edited/making_marriage_work.txt +15 -0
  211. data/zamples/edit_decision_lists/dvds/edls_being_edited/national_treasure.txt +26 -0
  212. data/zamples/edit_decision_lists/dvds/edls_being_edited/percy_jackson_lightening_thief.txt +40 -0
  213. data/zamples/edit_decision_lists/dvds/edls_being_edited/percy_jackson_lightening_thief_mute_scary.txt +23 -0
  214. data/zamples/edit_decision_lists/dvds/edls_being_edited/prince_of_egypt.txt +28 -0
  215. data/zamples/edit_decision_lists/dvds/edls_being_edited/puss_in_boots.txt +33 -0
  216. data/zamples/edit_decision_lists/dvds/edls_being_edited/ratatouille.txt +35 -0
  217. data/zamples/edit_decision_lists/dvds/edls_being_edited/rio.txt +24 -0
  218. data/zamples/edit_decision_lists/dvds/edls_being_edited/test_delete_list_for_experimenting_with.txt +10 -0
  219. data/zamples/edit_decision_lists/dvds/edls_being_edited/the_explorers.txt +49 -0
  220. data/zamples/edit_decision_lists/dvds/finding_neverland.txt +32 -0
  221. data/zamples/edit_decision_lists/dvds/flight_of_the_navigator.txt +40 -0
  222. data/zamples/edit_decision_lists/dvds/happiest baby on the block.txt +9 -0
  223. data/zamples/edit_decision_lists/dvds/harry_potter_3_prisoner_of_azkaban.txt +37 -0
  224. data/zamples/edit_decision_lists/dvds/hitchhiker's_guide_to_the_galaxy.txt +32 -0
  225. data/zamples/edit_decision_lists/dvds/how_to_train_your_dragon.txt +25 -0
  226. data/zamples/edit_decision_lists/dvds/if_a_man_answers.txt +43 -0
  227. data/zamples/edit_decision_lists/dvds/innerspace.txt +77 -0
  228. data/zamples/edit_decision_lists/dvds/iq.txt +32 -0
  229. data/zamples/edit_decision_lists/dvds/king_of_kings.txt +28 -0
  230. data/zamples/edit_decision_lists/dvds/kung_fu_panda_1.txt +17 -0
  231. data/zamples/edit_decision_lists/dvds/legend_of_the_guardians_the_owls_of_gahoole.txt +18 -0
  232. data/zamples/edit_decision_lists/dvds/monsters_vs_aliens.txt +41 -0
  233. data/zamples/edit_decision_lists/dvds/muppet_treasure_island.txt +21 -0
  234. data/zamples/edit_decision_lists/dvds/nanny_mcphee.txt +31 -0
  235. data/zamples/edit_decision_lists/dvds/narnia_voyage_of_the_dawn_treader.txt +16 -0
  236. data/zamples/edit_decision_lists/dvds/pack_jackson_wedding_2007-03-03.txt +31 -0
  237. data/zamples/edit_decision_lists/dvds/peter_pan.txt +29 -0
  238. data/zamples/edit_decision_lists/dvds/remember_the_titans.txt +35 -0
  239. data/zamples/edit_decision_lists/dvds/sintel_open_source_blender_ntsc_dvd.txt +22 -0
  240. data/zamples/edit_decision_lists/dvds/snow_white_and_the_7_dwarfs_1937.txt +19 -0
  241. data/zamples/edit_decision_lists/dvds/speed_racer.txt +47 -0
  242. data/zamples/edit_decision_lists/dvds/tangled.txt +21 -0
  243. data/zamples/edit_decision_lists/dvds/tron_legacy.txt +29 -0
  244. data/zamples/edit_decision_lists/dvds/turn_around_alma_younger.txt +17 -0
  245. data/zamples/edit_decision_lists/files/conference_music_video.txt +10 -0
  246. data/zamples/edit_decision_lists/netflix_instant/avatar-last-air-bender-movie.txt +13 -0
  247. data/zamples/edit_decision_lists/netflix_instant/avatar-last-airbender-series.txt +1 -0
  248. data/zamples/edit_decision_lists/netflix_instant/greatest_story_ever_told_netflix.txt +10 -0
  249. data/zamples/edit_decision_lists/netflix_instant/wrinkle-in-time.txt +23 -0
  250. data/zamples/edit_decision_lists/notes_on_movies_without_edls_yet/tron.txt +10 -0
  251. data/zamples/edit_decision_lists/old_not_yet_updated/dvds/White Christmas.txt +15 -0
  252. data/zamples/edit_decision_lists/old_not_yet_updated/dvds/all_dogs_go_to_heaven.txt +9 -0
  253. data/zamples/edit_decision_lists/old_not_yet_updated/dvds/cars_disney.txt +24 -0
  254. data/zamples/edit_decision_lists/old_not_yet_updated/dvds/happy_feet.txt +12 -0
  255. data/zamples/edit_decision_lists/old_not_yet_updated/dvds/labyrinth.txt +17 -0
  256. data/zamples/edit_decision_lists/old_not_yet_updated/dvds/star_trek_generations_hulu.txt +8 -0
  257. data/zamples/edit_decision_lists/old_not_yet_updated/example_edit_decision_list.txt +14 -0
  258. data/zamples/edit_decision_lists/old_not_yet_updated/youtube/gummy_bear_song_youtube.txt +9 -0
  259. data/zamples/edit_decision_lists/youtube/demo_mutes.txt +12 -0
  260. data/zamples/edit_decision_lists/youtube/nuki_song_youtube.txt +14 -0
  261. data/zamples/edit_decision_lists/youtube/nuki_song_youtube_pointer.txt +3 -0
  262. data/zamples/players/how_to_create_more_players.txt +24 -0
  263. data/zamples/players/hulu/total_length_over_an_hour.txt +25 -0
  264. data/zamples/players/netflix/netflix_firefox_non_maximized.txt +25 -0
  265. data/zamples/players/vlc/full_screened_total_length_over_an_hour.txt +27 -0
  266. data/zamples/players/vlc/windowed_total_length_over_an_hour.txt +26 -0
  267. data/zamples/players/vlc/windowed_total_length_under_an_hour.txt +22 -0
  268. data/zamples/players/youtube/full_screened_1024x768.txt +20 -0
  269. data/zamples/players/youtube/full_screened_1152x864.txt +20 -0
  270. data/zamples/players/youtube/full_screened_1680x1050.txt +20 -0
  271. data/zamples/players/youtube/normal_in_youtube.com.chrome.txt +23 -0
  272. data/zamples/players/youtube/note_these_assume_less_than_10_minutes_length.txt +2 -0
  273. metadata +483 -0
@@ -0,0 +1,60 @@
1
+ =begin
2
+ Copyright 2010, Roger Pack
3
+ This file is part of Sensible Cinema.
4
+
5
+ Sensible Cinema is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ Sensible Cinema is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Sensible Cinema. If not, see <http://www.gnu.org/licenses/>.
17
+ =end
18
+ require 'Win32API'
19
+
20
+ # does the jruby check inline
21
+
22
+ class KeyboardInput
23
+
24
+ def initialize fella
25
+ @fella = fella
26
+ end
27
+
28
+ def start_thread
29
+ Thread.new { loop {
30
+ print get_line_printout
31
+ sleep 0.1
32
+ } }
33
+ end
34
+
35
+ def get_line_printout
36
+ status = @fella.status
37
+ # some scary hard coded values here...LODO curses?
38
+ " " * 20 + "\b"*150 + status
39
+ end
40
+
41
+ def getch
42
+ @getch ||= Win32API.new('crtdll', '_getch', [], 'L')
43
+ @getch.call
44
+ end
45
+
46
+ def handle_keystrokes_forever
47
+ raise 'only jruby supported, as it looks just too messy in normal ruby' unless OS.java?
48
+ while(ch = getch)
49
+ exit if ch == 3 # ctrl+c
50
+ # lodo handle arrow keys, too, which is a bit more complicated...
51
+ handle_keystroke ch
52
+ end
53
+ end
54
+
55
+ def handle_keystroke ch
56
+ string = "" << ch
57
+ @fella.keyboard_input(string)
58
+ end
59
+
60
+ end
@@ -0,0 +1,27 @@
1
+ module MediaInfoParser
2
+ def self.parse_with_convert_command media_info, filename
3
+ video = audio = nil
4
+ media_info.split("Track ID").each{ |section|
5
+ section =~ /:(\W+)(\d+)/
6
+ id = $2
7
+ section =~ /Stream ID: (\S+)/ # like V_MPEG-2
8
+ stream_type = $1
9
+ if stream_type
10
+ raise unless id
11
+ if section =~ /Frame rate/ && !video
12
+ section =~ /Frame rate: ([\d\.]+)/
13
+ fps = $1
14
+ raise unless fps
15
+ raise unless section =~ /lang: eng/ # expect...
16
+ video = "#{stream_type}, \"#{filename}\", fps=#{fps}, track=#{id}, lang=eng"
17
+ elsif section =~ /Channels:/ && !audio
18
+ raise unless section =~ /lang: eng/ # hope english audio track comes first...
19
+ # A_AC3, "G:\Video\Sintel_NTSC\title01.mkv", track=2, lang=eng
20
+ audio = "#{stream_type}, \"#{filename}\", track=#{id}, lang=eng"
21
+ end
22
+ end
23
+ }
24
+ raise unless video && audio
25
+ return "MUXOPT --no-pcr-on-video-pid --new-audio-pes --vbr --vbv-len=500\n#{video}\n#{audio}"
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ =begin
2
+ Copyright 2010, Roger Pack
3
+ This file is part of Sensible Cinema.
4
+
5
+ Sensible Cinema is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ Sensible Cinema is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Sensible Cinema. If not, see <http://www.gnu.org/licenses/>.
17
+ =end
18
+ require './../lib/mouse.rb'
19
+ Mouse::jitter_forever_in_own_thread.join
@@ -0,0 +1,27 @@
1
+ module MovieHasher
2
+
3
+ CHUNK_SIZE = 64 * 1024 # in bytes
4
+
5
+ def self.compute_hash(filename)
6
+ filesize = File.size(filename)
7
+ hash = filesize
8
+
9
+ # Read 64 kbytes, divide up into 64 bits and add each
10
+ # to hash. Do for beginning and end of file.
11
+ File.open(filename, 'rb') do |f|
12
+ # Q = unsigned long long = 64 bit
13
+ f.read(CHUNK_SIZE).unpack("Q*").each do |n|
14
+ hash = hash + n & 0xffffffffffffffff # to remain as 64 bit number
15
+ end
16
+
17
+ f.seek([0, filesize - CHUNK_SIZE].max, IO::SEEK_SET)
18
+
19
+ # And again for the end of the file
20
+ f.read(CHUNK_SIZE).unpack("Q*").each do |n|
21
+ hash = hash + n & 0xffffffffffffffff
22
+ end
23
+ end
24
+
25
+ sprintf("%016x", hash)
26
+ end
27
+ end
@@ -0,0 +1,42 @@
1
+ =begin
2
+ Copyright 2010, Roger Pack
3
+ This file is part of Sensible Cinema.
4
+
5
+ Sensible Cinema is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ Sensible Cinema is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Sensible Cinema. If not, see <http://www.gnu.org/licenses/>.
17
+ =end
18
+
19
+ require_relative 'edl_parser'
20
+
21
+ class MplayerEdl
22
+
23
+ def self.convert_to_edl specs, add_this_many_to_end = 0, add_this_many_to_beginning = 0, splits = [], extra_time_to_all = 0.0, use_english_timestamps = false
24
+
25
+ # simple re-map to EDL style output
26
+ combined = EdlParser.convert_incoming_to_split_sectors specs, add_this_many_to_end, add_this_many_to_beginning, splits
27
+
28
+ out = ''
29
+ map = {:mute => 1, :blank => 0}
30
+ for start, endy, type in combined
31
+ start += extra_time_to_all
32
+ endy += extra_time_to_all
33
+ if use_english_timestamps
34
+ start = EdlParser.translate_time_to_human_readable start
35
+ endy = EdlParser.translate_time_to_human_readable endy
36
+ end
37
+ out += "#{start} #{endy} #{map[type]}\n"
38
+ end
39
+ out
40
+ end
41
+
42
+ end
@@ -0,0 +1,87 @@
1
+ =begin
2
+ Copyright 2010, Roger Pack
3
+ This file is part of Sensible Cinema.
4
+
5
+ Sensible Cinema is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ Sensible Cinema is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Sensible Cinema. If not, see <http://www.gnu.org/licenses/>.
17
+ =end
18
+ require 'rubygems' # ugh
19
+ require 'ffi'
20
+ require 'sane'
21
+ require_relative 'jruby-swing-helpers/mouse'
22
+ require_relative 'jruby-swing-helpers/play_audio'
23
+
24
+ module Muter
25
+ # from msdn on keybd_event ...
26
+
27
+ VK_VOLUME_DOWN = 0xAE
28
+ VK_VOLUME_UP = 0xAF
29
+ VK_VOLUME_MUTE = 0xAD
30
+ KEYEVENTF_KEYUP = 2
31
+
32
+ extend FFI::Library
33
+ ffi_lib 'user32'
34
+ ffi_convention :stdcall
35
+
36
+ attach_function :keybd_event, [ :uchar, :uchar, :int, :pointer ], :void
37
+
38
+ def hit_mute_key
39
+ # simulate pressing the mute key
40
+ keybd_event(VK_VOLUME_MUTE, 0, 0, nil)
41
+ keybd_event(VK_VOLUME_MUTE, 0, KEYEVENTF_KEYUP, nil)
42
+ end
43
+
44
+ def hit_volume_up_key
45
+ p 'hitting up volume key'
46
+ keybd_event(VK_VOLUME_UP, 0, 0, nil)
47
+ keybd_event(VK_VOLUME_UP, 0, KEYEVENTF_KEYUP, nil)
48
+ end
49
+
50
+ def hit_volume_down_key
51
+ p 'hitting down volume key'
52
+ keybd_event(VK_VOLUME_DOWN, 0, 0, nil)
53
+ keybd_event(VK_VOLUME_DOWN, 0, KEYEVENTF_KEYUP, nil)
54
+ end
55
+
56
+ def mute!
57
+ #unmute! # just in case...somehow this was causing problems...windows 7 perhaps? VLC?
58
+ # anyway we just use a toggle for now...dangerous but works hopefully...
59
+ if @@use_mouse_click
60
+ Mouse.single_click_left_mouse_button
61
+ else
62
+ hit_mute_key
63
+ end
64
+ end
65
+
66
+ @@use_mouse_click = true
67
+
68
+ # LODO better for doze 7/xp
69
+ def unmute!
70
+ if @@use_mouse_click
71
+ Mouse.single_click_left_mouse_button
72
+ elsif @@use_static_on_top
73
+ stop_playing_static
74
+ elsif @@use_down_volume_button
75
+ @@use_down_volume_button_number.times { hit_volume_up_key }
76
+ else
77
+ hit_mute_key # Windows XP...
78
+ hit_volume_down_key
79
+ hit_volume_up_key
80
+ end
81
+
82
+ end
83
+
84
+ # allow for Muter.xxx
85
+ extend self
86
+
87
+ end
@@ -0,0 +1,125 @@
1
+ =begin
2
+ Copyright 2010, Roger Pack
3
+ This file is part of Sensible Cinema.
4
+
5
+ Sensible Cinema is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ Sensible Cinema is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Sensible Cinema. If not, see <http://www.gnu.org/licenses/>.
17
+ =end
18
+ require 'sane' # gem
19
+ require 'whichr' # gem
20
+
21
+ # not a dependency yet, so I don't have to bundle it...
22
+ # im_path = File.expand_path(File.dirname(__FILE__) + "/../vendor/cache/imagemagick") # convert.exe wants to only be chosen from here...
23
+ # ENV['PATH'] = im_path.gsub('/', "\\") + ';' + ENV['PATH']
24
+
25
+ if RubyWhich.new.which('identify').length == 0 || RubyWhich.new.which('convert').length == 0
26
+ puts 'appears you do not have imagemagick installed (or not in your path) -- please download and install it first! http://www.imagemagick.org/script/binary-releases.php'
27
+ raise
28
+ end
29
+
30
+ # helper for OCR'ing single digits that were screen captured
31
+ module OCR
32
+ if OS.windows?
33
+ GOCR = File.expand_path(File.dirname(__FILE__) + "/../vendor/gocr049.exe -C 0-9:/ ")
34
+ else
35
+ require_relative 'check_installed_mac'
36
+ exit 1 unless CheckInstalledMac.check_for_installed 'gocr'
37
+ GOCR = "gocr"
38
+ end
39
+
40
+ CACHE = {}
41
+
42
+ # options are :might_be_colon, :should_invert
43
+ def identify_digit memory_bitmap, options = {}
44
+ require 'mini_magick' # here because of installation woe, but actually not a big slowdown
45
+
46
+ if CACHE.has_key?(memory_bitmap)
47
+ return CACHE[memory_bitmap] unless (defined?($OCR_NO_CACHE) && $OCR_NO_CACHE)
48
+ else
49
+ puts 'cache miss' if $DEBUG && $VERBOSE
50
+ end
51
+
52
+ if options[:might_be_colon]
53
+ # do special processing <sigh>
54
+ total = (memory_bitmap.scan(/\x00{5}+/)).length
55
+ if total >= 3 # really should be 4 for VLC
56
+ # it had some darkness...therefore have been a colon!
57
+ CACHE[memory_bitmap] = ":"
58
+ return ":"
59
+ end
60
+ end
61
+ image = MiniMagick::Image.read(memory_bitmap)
62
+ # any operation on image is expensive, requires convert.exe in path...
63
+ if options[:should_invert]
64
+ # hulu wants negate
65
+ # but doesn't want sharpen, for whatever reason...
66
+ # mogrify calls it negate...
67
+ image.negate
68
+ end
69
+
70
+ image.format(:pnm)
71
+ # I think it's VLC full screen that wants sharpening...
72
+ image.sharpen(2) if options[:sharpen] # hulu does *not* want sharpen, though I haven't checked it too closely...
73
+
74
+ previous = nil
75
+ p options if $DEBUG
76
+ raise 'you must pass in OCR levels in the player description' unless options[:levels]
77
+ for level in options[:levels]
78
+ command = "#{GOCR} -l #{level} #{image.path} 2>NUL"
79
+ a = `#{command}`
80
+ if a =~ /[0-9]/
81
+ # it might be funky like "_1_\n"
82
+ a.strip!
83
+ a.gsub!('_', '')
84
+ a = a.to_i
85
+ return CACHE[memory_bitmap] = a
86
+ end
87
+ end
88
+ # cache failures here, for VLC's hour clock' sake
89
+ CACHE[memory_bitmap] = nil
90
+ nil
91
+ end
92
+
93
+ def version
94
+ `#{GOCR} -h 2>&1`
95
+ end
96
+
97
+ def clear_cache!
98
+ CACHE.clear
99
+ File.delete CACHE_FILE if File.exist?(CACHE_FILE)
100
+ end
101
+
102
+ CACHE_FILE = File.expand_path('~/.sensible-cinema-ocr.marshal')
103
+
104
+ def serialize_cache_to_disk
105
+ File.binwrite(CACHE_FILE, Marshal.dump(CACHE))
106
+ end
107
+
108
+ def unserialize_cache_from_disk
109
+ if File.exist? CACHE_FILE
110
+ CACHE.merge!(Marshal.load(File.binread(CACHE_FILE)))
111
+ end
112
+ end
113
+
114
+ def load_from_ocr_seed
115
+ for file in Dir[__DIR__ + "/ocr_seed/*.bmp"]
116
+ file =~ /(\d+)\.bmp/i
117
+ digit = $1.to_i
118
+ raise unless digit < 10
119
+ CACHE[File.binread(file)] = digit
120
+ end
121
+ end
122
+
123
+ extend self
124
+
125
+ end
@@ -0,0 +1,373 @@
1
+ =begin
2
+ Copyright 2010, Roger Pack
3
+ This file is part of Sensible Cinema.
4
+
5
+ Sensible Cinema is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ Sensible Cinema is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Sensible Cinema. If not, see <http://www.gnu.org/licenses/>.
17
+ =end
18
+
19
+ require 'sane'
20
+ require 'thread'
21
+ require 'timeout'
22
+ require 'yaml'
23
+ require_relative 'muter'
24
+ require_relative 'blanker'
25
+ require_relative 'edl_parser'
26
+
27
+ require 'pp' # for pretty_inspect
28
+
29
+ class OverLayer
30
+
31
+ def muted?
32
+ @am_muted
33
+ end
34
+
35
+ def blank?
36
+ @am_blanked
37
+ end
38
+
39
+ def mute!
40
+ @am_muted = true
41
+ puts 'muting!' if $VERBOSE
42
+ Muter.mute! unless defined?($AM_IN_UNIT_TEST)
43
+ end
44
+
45
+ def unmute!
46
+ @am_muted = false
47
+ puts 'unmuting!' if $VERBOSE
48
+ Muter.unmute! unless defined?($AM_IN_UNIT_TEST)
49
+ end
50
+
51
+ def blank! seconds
52
+ @am_blanked = true
53
+ Blanker.blank_full_screen! seconds
54
+ end
55
+
56
+ def unblank!
57
+ @just_unblanked = true
58
+ @am_blanked = false
59
+ Blanker.unblank_full_screen!
60
+ end
61
+
62
+ def check_reload_yaml
63
+ current_mtime = File.stat(@filename).mtime
64
+ if @file_mtime != current_mtime
65
+ reload_yaml!
66
+ @file_mtime = current_mtime
67
+ else
68
+ #p 'same mtime:', @file_mtime if $DEBUG && $VERBOSE
69
+ end
70
+ end
71
+
72
+ attr_accessor :all_sequences
73
+
74
+ def reload_yaml!
75
+ @all_sequences = OverLayer.translate_file(@filename)
76
+ puts '(re) loaded mute sequences from ' + File.basename(@filename) + ' as', pretty_sequences.pretty_inspect, "" unless defined?($AM_IN_UNIT_TEST)
77
+ signal_change
78
+ end
79
+
80
+ def pretty_sequences
81
+ new_sequences = {}
82
+ @all_sequences.each{|type, values|
83
+ if values.is_a? Array
84
+ new_sequences[type] = values.map{|s, f|
85
+ [EdlParser.translate_time_to_human_readable(s), EdlParser.translate_time_to_human_readable(f)]
86
+ }
87
+ else
88
+ new_sequences[type] = values
89
+ end
90
+ }
91
+ new_sequences
92
+ end
93
+
94
+ def self.new_raw ruby_hash
95
+ File.write 'temp.yml', YAML.dump(ruby_hash)
96
+ OverLayer.new('temp.yml')
97
+ end
98
+
99
+ def initialize filename
100
+ @filename = filename
101
+ @am_muted = false
102
+ @am_blanked = false
103
+ @mutex = Mutex.new
104
+ @cv = ConditionVariable.new
105
+ @file_mtime = nil
106
+ check_reload_yaml
107
+ @just_unblanked = false
108
+ @start_time = Time.now_f # assume they want to start immediately...
109
+ end
110
+
111
+ # note this is actually deprecated and won't work anymore <sigh> and needs to be updated.
112
+ def self.translate_file filename
113
+ begin
114
+ all = EdlParser.parse_file(filename)
115
+ rescue NoMethodError, ArgumentError => e
116
+ p 'appears your file has a syntax error in it--perhaps missing quotation marks?', e.to_s
117
+ raise e # hope this is ok...
118
+ end
119
+
120
+ # now it's like {:mutes => {"1:02.0" => "1:3.0"}}
121
+ # translate to floats like 62.0 => 63.0
122
+
123
+ for type in [:mutes, :blank_outs] # LODO standardize these :mutes and :blank_outs somewhere...scary to have them repeated *everywhere*
124
+ maps = all[type] || all[type.to_s] || {}
125
+ new = {}
126
+ maps.each{|start,endy|
127
+ # both are like 1:02.0
128
+ start2 = EdlParser.translate_string_to_seconds(start) if start
129
+ endy2 = EdlParser.translate_string_to_seconds(endy) if endy
130
+ if start2 == 0 || endy2 == 0 || start == nil || endy == nil
131
+ p 'warning--possible error in the Edit Decision List file some line not parsed! (NB if you want one to start at time 0 please use 0.0001)', start, endy unless $AM_IN_UNIT_TEST
132
+ # drop this line into the bitbucket...
133
+ next
134
+ end
135
+
136
+ if start2 == endy2 || endy2 < start2
137
+ p 'warning--found a line that had poor interval', start, endy, type unless defined?($AM_IN_UNIT_TEST)
138
+ next
139
+ end
140
+ if(endy2 > 60*60*3)
141
+ p 'warning--found setting past 3 hours [?]', start, endy, type unless defined?($AM_IN_UNIT_TEST)
142
+ end
143
+ new[start2] = endy2
144
+ }
145
+ all.delete(type.to_s) # cleanup
146
+ all[type] = new.sort
147
+ end
148
+ all
149
+ end
150
+
151
+ def timestamp_changed to_this_exact_string_might_be_nil, delta
152
+ if @just_unblanked
153
+ # ignore it, since it was probably just caused by the screen blipping
154
+ # at worse this will put us 1s behind...hmm.
155
+ @just_unblanked = false
156
+ p 'ignoring timestamp update ' + to_this_exact_string_might_be_nil.to_s if $VERBOSE
157
+ else
158
+ set_seconds EdlParser.translate_string_to_seconds(to_this_exact_string_might_be_nil) + delta if to_this_exact_string_might_be_nil
159
+ end
160
+ end
161
+
162
+
163
+ # returns seconds it's at currently...
164
+ def cur_time
165
+ Time.now_f - @start_time
166
+ end
167
+
168
+ def cur_english_time
169
+ EdlParser.translate_time_to_human_readable(cur_time)
170
+ end
171
+
172
+ def status
173
+ time = cur_english_time
174
+ begin
175
+ mute, blank, next_sig = get_current_state
176
+ if next_sig == :done
177
+ state = " no more after this point..."
178
+ else
179
+ state = " next will be at #{EdlParser.translate_time_to_human_readable next_sig}s "
180
+ end
181
+ if blank? or muted?
182
+ state += "(" + [muted? ? "muted" : nil, blank? ? "blanked" : nil ].compact.join(' ') + ") "
183
+ end
184
+ end
185
+ check_reload_yaml
186
+ time + state + "(r [ctrl+c or q to quit]): "
187
+ end
188
+
189
+ def keyboard_input char
190
+ delta = case char
191
+ when 'h' then 60*60
192
+ when 'H' then -60*60
193
+ when 'm' then 60
194
+ when 'M' then -60
195
+ when 's' then 1
196
+ when 'S' then -1
197
+ when 't' then 0.1
198
+ when 'q' then
199
+ puts '','quitting'
200
+ exit(1)
201
+ when 'T' then -0.1
202
+ when 'v' then
203
+ $VERBOSE = !$VERBOSE
204
+ p 'set verbose to ', $VERBOSE
205
+ return
206
+ when 'd'
207
+ $DEBUG = !$DEBUG
208
+ p 'set debug to', $DEBUG
209
+ return
210
+ when ' ' then
211
+ puts 'timestamp:' + cur_english_time
212
+ return
213
+ when 'r' then
214
+ reload_yaml!
215
+ puts
216
+ return
217
+ else nil
218
+ end
219
+ if delta
220
+ set_seconds(cur_time + delta)
221
+ else
222
+ puts 'invalid char: [' + char + ']'
223
+ end
224
+ end
225
+
226
+ # sets it to a new set of seconds...
227
+ def set_seconds seconds
228
+ seconds = [seconds, 0].max
229
+ @mutex.synchronize {
230
+ @start_time = Time.now_f - seconds
231
+ }
232
+ signal_change
233
+ end
234
+
235
+ def signal_change
236
+ @mutex.synchronize {
237
+ # tell the driver thread to wake up and re-check state.
238
+ # We're not super thread friendly but good enough for having two contact each other...
239
+ @cv.signal
240
+ }
241
+ end
242
+
243
+ # we have a single scheduler thread, that is notified when the time may have changed
244
+ # like
245
+ # def restart new_time
246
+ # @current_time = xxx
247
+ # broadcast # things have changed
248
+ # end
249
+
250
+ def start_thread continue_forever = false
251
+ @thread = Thread.new { continue_until_past_all continue_forever }
252
+ end
253
+
254
+ def kill_thread!
255
+ @thread.kill
256
+ end
257
+
258
+ # returns [start, end, active|:done]
259
+ def discover_state type, cur_time
260
+ for start, endy in @all_sequences[type]
261
+ if cur_time < endy
262
+ # first one that we haven't passed the *end* of yet
263
+ if(cur_time >= start)
264
+ return [start, endy, true]
265
+ else
266
+ return [start, endy, false]
267
+ end
268
+ end
269
+
270
+ end
271
+ return [nil, nil, :done]
272
+ end
273
+
274
+ #
275
+ # returns [true, false, next_moment_of_importance|:done] ( true, false for if it should be currently muted, blanked )
276
+ #
277
+ def get_current_state
278
+ all = []
279
+ time = cur_time
280
+ for type in [:mutes, :blank_outs] do
281
+ all << discover_state(type, time)
282
+ end
283
+ output = []
284
+ # all is [[start, end, active]...] or [:done, :done]
285
+ earliest_moment = 1_000_000
286
+ all.each{|start, endy, active|
287
+ if active == :done
288
+ output << false
289
+ next
290
+ else
291
+ output << active
292
+ end
293
+ if active
294
+ earliest_moment = [earliest_moment, endy].min
295
+ else
296
+ earliest_moment = [earliest_moment, start].min
297
+ end
298
+ }
299
+ if earliest_moment == 1_000_000
300
+ output << :done
301
+ else
302
+ output << earliest_moment
303
+ end
304
+ output
305
+ end
306
+
307
+ def continue_until_past_all continue_forever
308
+ if RUBY_VERSION < '1.9.2'
309
+ raise 'need 1.9.2+ for MRI for the mutex stuff' unless RUBY_PLATFORM =~ /java/
310
+ end
311
+
312
+ @mutex.synchronize {
313
+ loop {
314
+ muted, blanked, next_point = get_current_state
315
+ if next_point == :done
316
+ if continue_forever
317
+ time_till_next_mute_starts = 1_000_000
318
+ else
319
+ #set_states! # for the unit tests' sake
320
+ return
321
+ end
322
+ else
323
+ time_till_next_mute_starts = next_point - cur_time
324
+ end
325
+
326
+ # pps 'sleeping until next action (%s) begins in %fs (%f) %f' % [next_point, time_till_next_mute_starts, Time.now_f, cur_time] if $VERBOSE
327
+
328
+ @cv.wait(@mutex, time_till_next_mute_starts) if time_till_next_mute_starts > 0
329
+ set_states!
330
+ }
331
+ }
332
+ end
333
+
334
+ def display_change change
335
+ puts '' unless defined?($AM_IN_UNIT_TEST)
336
+ if $VERBOSE
337
+ puts change + ' at ' + cur_english_time
338
+ end
339
+ end
340
+
341
+ def set_states!
342
+ should_be_muted, should_be_blank, next_point = get_current_state
343
+
344
+ if should_be_muted && !muted?
345
+ mute!
346
+ display_change 'muted'
347
+ end
348
+
349
+ if !should_be_muted && muted?
350
+ unmute!
351
+ display_change 'unmuted'
352
+ end
353
+
354
+ if should_be_blank && !blank?
355
+ blank! "%.02f" % (next_point - cur_time)
356
+ mute! # mute with blanks currently...
357
+ display_change 'blanked'
358
+ end
359
+
360
+ if !should_be_blank && blank?
361
+ unblank!
362
+ display_change 'unblanked'
363
+ end
364
+
365
+ end
366
+
367
+ end
368
+
369
+ class Time
370
+ def self.now_f
371
+ now.to_f
372
+ end
373
+ end