class EL_AUDIO_RMS_ENERGY

(source code)

Client examples: MULTIMEDIA_AUTOTEST_APP

description

Root Mean Square (RMS) audio wave energy

note
	description: "Root Mean Square (RMS) audio wave energy"

	author: "Finnian Reilly"
	copyright: "Copyright (c) 2001-2022 Finnian Reilly"
	contact: "finnian at eiffel hyphen loop dot com"

	license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
	date: "2024-01-21 13:08:27 GMT (Sunday 21st January 2024)"
	revision: "5"

class
	EL_AUDIO_RMS_ENERGY

inherit
	EL_AUDIO_SAMPLE_PROCESSOR

	DOUBLE_MATH
		rename
			log as logarithm
		end

	EL_EVENT_CHECKER

create
	make

feature {NONE} -- Initialization

	make (block_duration_millisecs: INTEGER)
			--
		do
			block_duration := (block_duration_millisecs / 1000.0).truncated_to_real
		end

feature -- Basic operations

	calculate (sample_source: EL_AUDIO_IO_MEDIUM)
			--
		do
			create rms_array.make (1, (sample_source.duration / block_duration).ceiling )
			block_index := 1
			sample_square_sum := 0
			rms_block_offset := block_duration
			rms_sum_over_threshold := 0
			rms_count_over_threshold := 0
			sample_source.set_channel_processor (Current, 1)

			sample_source.process_at_sample_rate ((1.0 / block_duration * Samples_per_block).rounded)
			rms_mean_over_threshold := (rms_sum_over_threshold.to_double / rms_count_over_threshold).rounded
		end

feature -- Access

	rms_array: ARRAY [INTEGER]

	rms_mean_over_threshold: INTEGER

	block_duration: REAL

	mean_over_threshold: INTEGER

feature {NONE} -- Implementation

	do_with_sample_at_time (value, index: INTEGER; offset_time: REAL)
			--
		local
			rms_value: INTEGER
		do
			if offset_time > rms_block_offset then
				rms_value  := sqrt (sample_square_sum.to_double).rounded
				rms_array [block_index] := rms_value
				if rms_value > Signal_threshold then
					rms_sum_over_threshold := rms_sum_over_threshold + rms_value
					rms_count_over_threshold := rms_count_over_threshold + 1
				end
				block_index := block_index + 1
				rms_block_offset := block_duration * block_index
				sample_square_sum := 0

				-- Intended for UI events
			end
			sample_square_sum := sample_square_sum + value * value

			check_events
		end

	do_with_sample (value, index: INTEGER)
			-- Not used
		do
		end

	rms_sum_over_threshold: INTEGER_64

	rms_count_over_threshold: INTEGER

	sample_square_sum: INTEGER_64

	block_index: INTEGER

	rms_block_offset: REAL

feature -- Constants

	Signal_threshold: INTEGER = 1000
			-- Minimum level

	Samples_per_block: INTEGER = 8
			-- Number of representative samples per block to calculate
			-- More means more accurate but slower

end