_vu-meters.tcl 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. # VU-meters, just for fun.
  2. #
  3. # Search in the script for 'customized' to see what you could customize ;-)
  4. #
  5. # The volume calculations are the volume setting of the channel, unless nothing
  6. # is played, then 0 is output. This is done by looking at 'key on' bits, as far
  7. # as they exist.
  8. #
  9. # TODO:
  10. # - optimize more?
  11. # - handle insertion/removal of sound devices (needs openMSX changes)
  12. #
  13. # Thanks to BiFi for helping out with the expressions for the devices.
  14. # Thanks to Wouter for the Tcl support.
  15. set_help_text toggle_vu_meters \
  16. {Puts a rough volume unit display for each channel and for all sound chips on
  17. the On-Screen-Display. Use the command again to remove it. Note: it cannot
  18. handle run-time insertion/removal of sound devices. It can handle changing
  19. of machines, though. Not all chips are supported yet.
  20. Note that displaying these VU-meters may cause quite some CPU load!}
  21. namespace eval vu_meters {
  22. variable vu_meters_active false
  23. variable volume_cache
  24. variable volume_expr
  25. variable bar_length
  26. variable machine_switch_trigger_id 0
  27. variable frame_trigger_id 0
  28. proc vu_meters_init {} {
  29. variable volume_cache
  30. variable volume_expr
  31. variable bar_length
  32. variable machine_switch_trigger_id
  33. # create root object for vu_meters
  34. osd create rectangle vu_meters \
  35. -scaled true \
  36. -alpha 0 \
  37. -z 1
  38. foreach soundchip [machine_info sounddevice] {
  39. # skip devices which don't have volume expressions (not implemented yet)
  40. if {[soundchip_utils::get_volume_expr $soundchip 0] eq "x"} continue
  41. # determine number of channels
  42. set channel_count [soundchip_utils::get_num_channels $soundchip]
  43. for {set i 0} {$i < $channel_count} {incr i} {
  44. # create the volume cache and the expressions
  45. dict set volume_cache $soundchip $i -1
  46. dict set volume_expr $soundchip $i [soundchip_utils::get_volume_expr $soundchip $i]
  47. }
  48. }
  49. set nof_soundchips [dict size $volume_expr]
  50. set bar_width 2; # this value could be customized
  51. set vu_meter_title_height 8; # this value could be customized
  52. set bar_length [expr {(320 - $nof_soundchips) / $nof_soundchips}]
  53. if {$bar_length > (320 / 4)} {set bar_length [expr {320 / 4}]}
  54. # create widgets for each sound chip:
  55. set vu_meter_offset 0
  56. dict for {soundchip channel_dict} $volume_expr {
  57. set nof_channels [dict size $channel_dict]
  58. # create surrounding widget for this chip
  59. osd create rectangle vu_meters.$soundchip \
  60. -rgba 0x00000080 \
  61. -x ${vu_meter_offset} \
  62. -y 0 \
  63. -w $bar_length \
  64. -h [expr {$vu_meter_title_height + 1 + $nof_channels * ($bar_width + 1)}] \
  65. -clip true
  66. osd create text vu_meters.${soundchip}.title \
  67. -x 1 \
  68. -y 1 \
  69. -rgba 0xffffffff \
  70. -text $soundchip \
  71. -size [expr {$vu_meter_title_height - 1}]
  72. # create vu meters for this sound chip
  73. dict for {channel volExpr} $channel_dict {
  74. osd create rectangle vu_meters.${soundchip}.ch${channel} \
  75. -rgba 0xff0000ff \
  76. -x 0 \
  77. -y [expr {$vu_meter_title_height + 1 + (($bar_width + 1) * $channel)}] \
  78. -w 0 \
  79. -h $bar_width \
  80. }
  81. incr vu_meter_offset [expr {$bar_length + 1}]
  82. }
  83. set machine_switch_trigger_id [after machine_switch [namespace code vu_meters_reset]]
  84. }
  85. proc update_meters {} {
  86. variable vu_meters_active
  87. variable volume_cache
  88. variable volume_expr
  89. variable frame_trigger_id
  90. # update meters with the volumes
  91. if {!$vu_meters_active} return
  92. if {[catch {
  93. dict for {soundchip channel_dict} $volume_expr {
  94. dict for {channel volExpr} $channel_dict {
  95. set new_volume [eval $volExpr]
  96. if {[dict get $volume_cache $soundchip $channel] != $new_volume} {
  97. dict set volume_cache $soundchip $channel $new_volume
  98. update_meter "vu_meters.${soundchip}.ch${channel}" $new_volume
  99. }
  100. }
  101. }
  102. }]} {
  103. # a chip disappeared probably, let's reinit to see which there are now
  104. vu_meters_reinit
  105. }
  106. # here you can customize the update frequency (to reduce CPU load)
  107. #set frame_trigger_id [after time 0.05 [namespace code update_meters]]
  108. set frame_trigger_id [after frame [namespace code update_meters]]
  109. }
  110. proc update_meter {meter volume} {
  111. variable bar_length
  112. set byte_val [expr {round(255 * $volume)}]
  113. set col1 0x008000C0
  114. set col2 [expr {($byte_val << 24) + $col1}]
  115. osd configure $meter \
  116. -w [expr {$bar_length * $volume}] \
  117. -rgba "$col1 $col2 $col1 $col2"
  118. }
  119. proc vu_meters_reset {} {
  120. variable vu_meters_active
  121. if {!$vu_meters_active} {
  122. error "Please fix a bug in this script!"
  123. }
  124. toggle_vu_meters
  125. toggle_vu_meters
  126. }
  127. proc toggle_vu_meters {} {
  128. variable vu_meters_active
  129. variable machine_switch_trigger_id
  130. variable frame_trigger_id
  131. variable bar_length
  132. variable volume_cache
  133. variable volume_expr
  134. if {$vu_meters_active} {
  135. after cancel $machine_switch_trigger_id
  136. after cancel $frame_trigger_id
  137. set vu_meters_active false
  138. osd destroy vu_meters
  139. unset bar_length volume_cache volume_expr
  140. } else {
  141. set vu_meters_active true
  142. vu_meters_init
  143. update_meters
  144. }
  145. return ""
  146. }
  147. proc vu_meters_reinit {} {
  148. toggle_vu_meters
  149. toggle_vu_meters
  150. }
  151. namespace export toggle_vu_meters
  152. } ;# namespace vu_meters
  153. namespace import vu_meters::*