message: add #within to Section

diff:
@@ -13,6 +13,11 @@ Feature: Page Sections
Then I can access elements within the section using a block
But I cannot access elements that are not in the section using a block
+ Scenario: access elements in the section by passing a block to within
+ When I navigate to the home page
+ Then I can execute elements in the context of a section by passing a block to within
+ But I cannot access elements that are not in the section using within
+
Scenario: section in a section
When I navigate to the nested section page
Then I can see a section in a section

diff:
@@ -27,12 +27,34 @@ Then('I can access elements within the section using a block') do
expect(block_inner_executions).to eq 1
end
+Then('I can execute elements in the context of a section by passing a block to within') do
+ block_inner_executions = 0
+
+ expect(@test_site.home).to have_people
+
+ @test_site.home.people.within do |section|
+ block_inner_executions += 1
+
+ expect(section.headline.text).to eq('People')
+
+ expect(section).to have_individuals(count: 4)
+ end
+
+ expect(block_inner_executions).to eq 1
+end
+
Then('I cannot access elements that are not in the section using a block') do
expect do
@test_site.home.people { |section| expect(section).to have_not_here }
end.to raise_error(RSpec::Expectations::ExpectationNotMetError)
end
+Then('I cannot access elements that are not in the section using within') do
+ expect do
+ @test_site.home.people.within { |section| expect(section).to have_not_here }
+ end.to raise_error(RSpec::Expectations::ExpectationNotMetError)
+end
+
Then('access to elements is constrained to those within the section') do
expect(@test_site.home).to have_css('.welcome')

diff:
@@ -31,6 +31,10 @@ module SitePrism
Capybara.within(@root_element) { yield(self) } if block_given?
end
+ def within(&block)
+ Capybara.within(@root_element) { yield(self) }
+ end
+
# Capybara::DSL module "delegates" Capybara methods to the "page" method
# as such we need to overload this method so that the correct scoping
# occurs and calls within a section (For example section.find(element))

diff:
@@ -77,6 +77,7 @@ describe SitePrism::Section do
it { is_expected.to respond_to(:wait_until_section_visible) }
it { is_expected.to respond_to(:wait_until_section_invisible) }
it { is_expected.to respond_to(:all_there?) }
+ it { is_expected.to respond_to(:within) }
end
context 'when second argument is not a Class but a block is given' do
@@ -96,6 +97,7 @@ describe SitePrism::Section do
it { is_expected.to respond_to(:wait_until_anonymous_section_visible) }
it { is_expected.to respond_to(:wait_until_anonymous_section_invisible) }
it { is_expected.to respond_to(:all_there?) }
+ it { is_expected.to respond_to(:within) }
end
context 'when second argument is a Class and a block is given' do
@@ -115,6 +117,7 @@ describe SitePrism::Section do
it { is_expected.to respond_to(:wait_until_anonymous_section_visible) }
it { is_expected.to respond_to(:wait_until_anonymous_section_invisible) }
it { is_expected.to respond_to(:all_there?) }
+ it { is_expected.to respond_to(:within) }
end
context 'when second argument is not a Class and no block is given' do
@@ -278,6 +281,14 @@ set_default_search_arguments within section class"
end
end
+ describe '#within' do
+ it "passes the block to Capybara#within" do
+ expect(Capybara).to receive(:within).with(locator)
+
+ section_without_block.within { :noop }
+ end
+ end
+
describe '#visible?' do
it 'delegates through root_element' do
expect(locator).to receive(:visible?)

original_message: add #within to Section


message: fix link to HACKING.md (used to be development.md per a1d22d

change_type: MODIFY

diff:
@@ -15,7 +15,7 @@ Make sure to add your project/company to https://github.com/site-prism/site_pris
We love it when people want to get involved with our Open Source Project.
-We have a brief set of setup docs [HERE](https://github.com/site-prism/site_prism/blob/master/development_setup.md)
+We have a brief set of setup docs [HERE](https://github.com/site-prism/site_prism/blob/master/HACKING.md)
## Supported Rubies / Browsers

license: BSD 3-Clause New or Revised License


message: update related block in section cukes in sections

diff:
@@ -16,6 +16,6 @@ Feature: Interaction with groups of elements
When I navigate to the nested section page
Then I can see a collection of anonymous sections
- Scenario: access elements in the section by passing a block
+ Scenario: can access elements in the section by passing a block to within
When I navigate to the nested section page
- Then I can execute in the context of a section using a block
+ Then I can execute in the context of each section by passing a block to within

diff:
@@ -18,21 +18,21 @@ Then('I can see a collection of anonymous sections') do
expect(anonymous_sections.size).to eq(2)
end
-
-Then('I can execute in the context of a section using a block') do
+Then('I can execute in the context of each section by passing a block to within') do
block_inner_executions = 0
expect(@test_site.nested_sections).to have_search_results(count: 4)
- @test_site.nested_sections.search_results.first do |sec|
+ @test_site.nested_sections.search_results.first.within do |sec|
block_inner_executions += 1
- expect(sec).to be_an_instance_of(SitePrism::Section)
+
+ expect(sec).to be_an_instance_of(SearchResults)
expect(sec).to have_text('Result 0')
end
- @test_site.nested_sections.search_results.last do |sec|
+ @test_site.nested_sections.search_results.last.within do |sec|
block_inner_executions += 1
- expect(sec).to be_an_instance_of(SitePrism::Section)
+ expect(sec).to be_an_instance_of(SearchResults)
expect(sec).to have_text('Result 3')
end


message:
debuggers make life better, and pry is the best debugger
dev dependency

diff:
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
s.add_dependency 'site_prism-all_there', ['>= 0.3.1', '< 1.0']
s.add_development_dependency 'cucumber', ['~> 3.1']
+ s.add_development_dependency 'pry-byebug'
s.add_development_dependency 'rake', ['>= 12.3']
s.add_development_dependency 'rspec', ['~> 3.8']
s.add_development_dependency 'rubocop', ['~> 0.75.0']

original_message:
debuggers make life better, and pry is the best debugger
- dev dependency


message: fix SimpleCov to keep track properly in cukes

diff:
@@ -15,6 +15,8 @@ require 'site_prism'
require_relative 'js_helper'
require_relative 'sections/all'
+SimpleCov.start if defined? SimpleCov
+
Capybara.register_driver :site_prism do |app|
browser = ENV.fetch('browser', 'firefox').to_sym
# Needed whilst we support Webdriver 3.x (Can be removed once we only support 4.x)


message: Document using #within

diff:
@@ -921,14 +921,13 @@ end
##### Accessing section elements using a block
-A Section can be scoped so it is only accessible inside a block. This is
+You can execute a block within the context of a Section. This is
similar to Capybara's `within` method and allows for shorter test code
-particularly with nested sections. Some of this test code can be
-made a little prettier by simply passing a block in.
+particularly with nested sections. Test code that might have to repeat the block name can be shortened up this way.
```ruby
Then(/^the home page menu contains a link to the various search functions$/) do
- @home.menu do |menu|
+ @home.menu.within do |menu|
expect(menu).to have_search
expect(menu.search['href']).to include('google.com')
expect(menu).to have_images
@@ -937,6 +936,16 @@ Then(/^the home page menu contains a link to the various search functions$/) do
end
```
+Note that on individual sections it's possible to pass a block directly to the section without using `within`. Because the block is executed only during Section initialization this won't work when accessing a single Section from an array of Sections. For that reason we recommend using `within` which works in either case.
+
+```ruby
+Then(/^the home page menu contains a link to the various search functions$/) do
+ @home.menu do |menu| # possible, but prefer: `@home.menu.within`
+ expect(menu).to have_search
+ end
+end
+```
+
#### Getting a section's parent
It is possible to ask a section for its parent (page, or section if this
@@ -1191,6 +1200,26 @@ element. So if the css selector finds 3 `li` elements, calling
`search_results` will return an array containing 3 instances of
`SearchResults`, each with one of the `li` elements as it's root element.
+##### Accessing Within a Collection of Sections
+
+When using an iterator such as `each` to pass a block through to a collection of sections it is possible to skip using `within`. However some caution is warranted when accessing the Sections directly from an array, as the block can only be executed when the section is being initialized. The following does not work:
+
+```rb
+ @home.search_results.first do |result|
+ # This block is silently ignored.
+ expect(result).to have_title
+ end
+```
+Instead use `within` to access the inner-context of the Section.
+
+```rb
+ @home.search_results.first.within do |result|
+ # This block is run within the context of the Section.
+ expect(result).to have_title
+ end
+```
+
+
#### Anonymous Section Collections
You can define collections of anonymous sections the same way you would

original_message: Document using #within


message: minor tweak to test to indicate that iterators still function

diff:
@@ -36,5 +36,12 @@ Then('I can execute in the context of each section by passing a block to within'
expect(sec).to have_text('Result 3')
end
- expect(block_inner_executions).to eq 2
+ @test_site.nested_sections.search_results.each do |sec|
+ block_inner_executions += 1
+
+ expect(sec).to be_an_instance_of(SearchResults)
+ expect(sec).to have_text(/Result/)
+ end
+
+ expect(block_inner_executions).to eq 6
end


message: doc: minor fix to README

diff:
@@ -936,7 +936,7 @@ Then(/^the home page menu contains a link to the various search functions$/) do
end
```
-Note that on individual sections it's possible to pass a block directly to the section without using `within`. Because the block is executed only during Section initialization this won't work when accessing a single Section from an array of Sections. For that reason we recommend using `within` which works in either case.
+Note that on an individual section it's possible to pass a block directly to the section without using `within`. Because the block is executed only during `Section` initialization this won't work when accessing a single Section from an array of Sections. For that reason we recommend using `within` which works in either case.
```ruby
Then(/^the home page menu contains a link to the various search functions$/) do

original_message: doc: minor fix to README


message: chore: delegate to #within from Section initializer

diff:
@@ -25,10 +25,10 @@ module SitePrism
nil
end
- def initialize(parent, root_element)
+ def initialize(parent, root_element, &block)
@parent = parent
@root_element = root_element
- Capybara.within(@root_element) { yield(self) } if block_given?
+ within(&block) if block_given?
end
def within


message: chore!: limit capybara to less than 3.30 due to breaking change

diff:
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
s.files = Dir.glob('lib/**/*') + %w[LICENSE.md README.md]
s.require_path = 'lib'
s.add_dependency 'addressable', ['~> 2.5']
- s.add_dependency 'capybara', ['~> 3.3']
+ s.add_dependency 'capybara', ['<= 3.29']
s.add_dependency 'site_prism-all_there', ['>= 0.3.1', '< 1.0']
s.add_development_dependency 'cucumber', ['~> 3.1']


message: Started refactorization by creating make_histogram function and renaming some variables.

diff:
@@ -122,50 +122,13 @@ class Duet(separation_base.SeparationBase):
# Calculate the symmetric attenuation (alpha) and delay (delta) for each
# time-freq. point
- R21 = (stft_ch1 + constants.EPSILON) / (stft_ch0 + constants.EPSILON)
- atn = np.abs(R21) # relative attenuation between the two channels
+ r21 = (stft_ch1 + constants.EPSILON) / (stft_ch0 + constants.EPSILON)
+ atn = np.abs(r21) # relative attenuation between the two channels
alpha = atn - 1 / atn # symmetric attenuation
- delta = -np.imag(np.log(R21)) / (2 * np.pi * wmat) # relative delay
+ delta = -np.imag(np.log(r21)) / (2 * np.pi * wmat) # relative delay
- # What is going on here???
- # ------------------------------------
- # calculate the weighted histogram
- p = 1
- q = 0
- tfw = (np.abs(stft_ch0) * np.abs(stft_ch1)) ** p * (np.abs(wmat)) ** q # time-freq weights
-
- # only consider time-freq. points yielding estimates in bounds
- a_premask = np.logical_and(self.attenuation_min < alpha, alpha < self.attenuation_max)
- d_premask = np.logical_and(self.delay_min < delta, delta < self.delay_max)
- ad_premask = np.logical_and(a_premask, d_premask)
-
- ad_nzind = np.nonzero(ad_premask)
- alpha_vec = alpha[ad_nzind]
- delta_vec = delta[ad_nzind]
- tfw_vec = tfw[ad_nzind]
-
- # compute the histogram
- H = np.histogram2d(alpha_vec, delta_vec, bins=np.array([self.num_attenuation_bins, self.num_delay_bins]),
- range=np.array([[self.attenuation_min, self.attenuation_max],
- [self.delay_min, self.delay_max]]), normed=False,
- weights=tfw_vec)
-
- hist = H[0] / H[0].max()
- agrid = H[1]
- dgrid = H[2]
-
- # Save these for later
- self.attenuation_grid = agrid
- self.delay_grid = dgrid
- self.attenuation_delay_histogram = hist
- self.non_normalized_hist = H[0]
- self.smoothed_hist = self._smooth_matrix(self.non_normalized_hist, np.array([3]))
-
- # smooth the histogram - local average 3-by-3 neighboring bins
- hist = self._smooth_matrix(hist, np.array([3]))
-
- # normalize and plot the histogram
- hist /= hist.max()
+ # make histogram
+ hist = self.make_histogram(stft_ch0, stft_ch1, wmat)
# find the location of peaks in the alpha-delta plane
self.peak_indices = self.find_peaks2(hist, self.peak_threshold,
@@ -209,6 +172,48 @@ class Duet(separation_base.SeparationBase):
return xhat, ad_est
+ def make_histogram(self, stft_ch0, stft_ch1, wmat):
+ # What is going on here???
+ # ------------------------------------
+ # calculate the weighted histogram
+ p = 1
+ q = 0
+ tfw = (np.abs(stft_ch0) * np.abs(stft_ch1)) ** p * (np.abs(wmat)) ** q # time-freq weights
+
+ # only consider time-freq. points yielding estimates in bounds
+ a_premask = np.logical_and(self.attenuation_min < alpha, alpha < self.attenuation_max)
+ d_premask = np.logical_and(self.delay_min < delta, delta < self.delay_max)
+ ad_premask = np.logical_and(a_premask, d_premask)
+
+ ad_nzind = np.nonzero(ad_premask)
+ alpha_vec = alpha[ad_nzind]
+ delta_vec = delta[ad_nzind]
+ tfw_vec = tfw[ad_nzind]
+
+ # compute the histogram
+ H = np.histogram2d(alpha_vec, delta_vec, bins=np.array([self.num_attenuation_bins, self.num_delay_bins]),
+ range=np.array([[self.attenuation_min, self.attenuation_max],
+ [self.delay_min, self.delay_max]]), normed=False,
+ weights=tfw_vec)
+
+ hist = H[0] / H[0].max()
+ agrid = H[1]
+ dgrid = H[2]
+
+ # Save these for later
+ self.attenuation_grid = agrid
+ self.delay_grid = dgrid
+ self.attenuation_delay_histogram = hist
+ self.non_normalized_hist = H[0]
+ self.smoothed_hist = self._smooth_matrix(self.non_normalized_hist, np.array([3]))
+
+ # smooth the histogram - local average 3-by-3 neighboring bins
+ hist = self._smooth_matrix(hist, np.array([3]))
+
+ # normalize and plot the histogram
+ hist /= hist.max()
+ return hist
+
@staticmethod
def find_peaks2(data, min_thr=0.5, min_dist=None, max_peaks=1):
"""Receives a matrix of positive numerical values (in [0,1]) and finds the peak values and corresponding

license: MIT License

repo: nussl/nussl


message: First draft of refactorized duet.run in Duet.py.

diff:
@@ -74,12 +74,18 @@ class Duet(separation_base.SeparationBase):
self.smoothed_hist = None
self.peak_indices = None
+ self.num_frequency_bins = None
+ self.num_time_bins = None
+ self.stft_ch0 = None
+ self.stft_ch = None
+ self.wmat = None
+
def run(self):
"""Extracts N sources from a given stereo audio mixture (N sources captured via 2 sensors)
Returns:
- * **xhat** (*np.array*) - an N-row matrix containing time-domain estimates of sources
- * **ad_est** (*np.array*) - N by 2 Numpy matrix containing estimated attenuation and delay values
+ * **source_estimates** (*np.array*) - an N-row matrix containing time-domain estimates of sources
+ * **atn_delay_est** (*np.array*) - N by 2 Numpy matrix containing estimated attenuation and delay values
corresponding to N sources
Example:
::
@@ -93,112 +99,117 @@ class Duet(separation_base.SeparationBase):
"""
- if self.audio_signal.num_channels != 2: # double check this
- raise ValueError('Cannot run Duet on audio signal without exactly 2 channels!')
-
# Give them shorter names
L = self.stft_params.window_length
win_type = self.stft_params.window_type
hop = self.stft_params.hop_length
fs = self.sample_rate
- # Compute the stft of the two channel mixtures
- self.audio_signal.stft_params = self.stft_params
- self.audio_signal.stft()
-
- stft_ch0 = self.audio_signal.get_stft_channel(0)
- stft_ch1 = self.audio_signal.get_stft_channel(1)
- frequency_vector = self.audio_signal.freq_vector
- time_vector = self.audio_signal.time_bins_vector
-
- # remove dc component to avoid dividing by zero freq. in the delay estimation
- stft_ch0 = stft_ch0[1::, :]
- stft_ch1 = stft_ch1[1::, :]
- num_frequency_bins = len(frequency_vector)
- num_time_bins = len(time_vector)
-
- # Compute the freq. matrix for later use in phase calculations
- wmat = np.array(np.tile(np.mat(frequency_vector[1::]).T, (1, num_time_bins))) * (2 * np.pi / fs) # WTF?
+ # Calculate the stft of both channels and create the frequency matrix
+ self.stft_ch0, self.stft_ch1, self.wmat = self.setup_duet(fs)
# Calculate the symmetric attenuation (alpha) and delay (delta) for each
# time-freq. point
- r21 = (stft_ch1 + constants.EPSILON) / (stft_ch0 + constants.EPSILON)
+ r21 = (self.stft_ch1 + constants.EPSILON) / (self.stft_ch0 + constants.EPSILON)
atn = np.abs(r21) # relative attenuation between the two channels
- alpha = atn - 1 / atn # symmetric attenuation
- delta = -np.imag(np.log(r21)) / (2 * np.pi * wmat) # relative delay
+ symmetric_atn = atn - 1 / atn # symmetric attenuation
+ delay = -np.imag(np.log(r21)) / (2 * np.pi * self.wmat) # relative delay
- # make histogram
- hist = self.make_histogram(stft_ch0, stft_ch1, wmat)
+ # make histogram and grids
+ hist, agrid, dgrid = self.make_histogram(symmetric_atn, delay)
- # find the location of peaks in the alpha-delta plane
+ # find the location of peaks in the symmetric_atn-delay plane
self.peak_indices = self.find_peaks2(hist, self.peak_threshold,
np.array([self.attenuation_min_distance, self.delay_min_distance]),
self.num_sources)
- alphapeak = agrid[self.peak_indices[0, :]]
- deltapeak = dgrid[self.peak_indices[1, :]]
-
- ad_est = np.vstack([alphapeak, deltapeak]).T
-
- # convert alpha to a
- atnpeak = (alphapeak + np.sqrt(alphapeak ** 2 + 4)) / 2
+ # compute delay_peak, attenuation peak, and attenuation/delay estimates
+ delay_peak, atn_delay_est, atnpeak = self.convert_peaks(agrid, dgrid)
# compute masks for separation
- bestsofar = np.inf * np.ones((num_frequency_bins - 1, num_time_bins))
- bestind = np.zeros((num_frequency_bins - 1, num_time_bins), int)
- for i in range(0, self.num_sources):
- score = np.abs(atnpeak[i] * np.exp(-1j * wmat * deltapeak[i]) * stft_ch0 - stft_ch1) ** 2 / \
- (1 + atnpeak[i] ** 2)
- mask = (score < bestsofar)
- bestind[mask] = i
- bestsofar[mask] = score[mask]
+ bestind, mask = self.compute_masks(atnpeak, delay_peak)
# demix with ML alignment and convert to time domain
- xhat = np.zeros((self.num_sources, self.audio_signal.signal_length))
- for i in range(0, self.num_sources):
- mask = (bestind == i)
- Xm = np.vstack([np.zeros((1, num_time_bins)),
- (stft_ch0 + atnpeak[i] * np.exp(1j * wmat * deltapeak[i]) * stft_ch1) /
- (1 + atnpeak[i] ** 2) * mask])
- # xi = spectral_utils.f_istft(Xm, L, winType, hop, fs)
- xi = spectral_utils.e_istft(Xm, L, hop, win_type)
+ source_estimates = self.convert_time_domain(bestind, mask, atnpeak, delay_peak)
- xhat[i, :] = utils.add_mismatched_arrays(xhat[i, ], xi)[:self.audio_signal.signal_length]
- # add back to the separated signal a portion of the mixture to eliminate
- # most of the masking artifacts
- # xhat=xhat+0.05*x[0,:]
+ self.separated_sources = source_estimates
+ return source_estimates, atn_delay_est
+
+ def setup_duet(self, fs):
+ """ Creates the stfts matrices for channel 0 and 1, and computes the frequency matrix.
+ Parameter:
+ fs (integer): sample rate
- self.separated_sources = xhat
+ Returns:
+ stft_ch0 (np.matrix): a 2D Numpy matrix containing the stft of channel 0
+ stft_ch1 (np.matrix): a 2D Numpy matrix containing the stft of channel 1
+ wmat: a frequency matrix
+ """
+ if self.audio_signal.num_channels != 2: # double check this
+ raise ValueError('Cannot run Duet on audio signal without exactly 2 channels!')
- return xhat, ad_est
+ # Compute the stft of the two channel mixtures
+ self.audio_signal.stft_params = self.stft_params
+ self.audio_signal.stft()
+
+ stft_ch0 = self.audio_signal.get_stft_channel(0)
+ stft_ch1 = self.audio_signal.get_stft_channel(1)
+ frequency_vector = self.audio_signal.freq_vector
+ time_vector = self.audio_signal.time_bins_vector
+
+ # remove dc component to avoid dividing by zero freq. in the delay estimation
+ stft_ch0 = stft_ch0[1::, :]
+ stft_ch1 = stft_ch1[1:, :]
+ self.num_frequency_bins = len(frequency_vector)
+ self.num_time_bins = len(time_vector)
+
+ # Compute the freq. matrix for later use in phase calculations
+ wmat = np.array(np.tile(np.mat(frequency_vector[1:]).T, (1, self.num_time_bins))) * (2 * np.pi / fs) # WTF?
+
+ return stft_ch0, stft_ch1, wmat
+
+ def make_histogram(self, symmetric_atn, delay):
+ """Receives the stft of the two channel mixtures and the frequency matrix to a create a smooth and normalized histogram.
+
+ Parameters:
+ stft_ch0 (): a 2D Numpy matrix containing the stft of channel 0
+ stft_ch1 (): a 2D Numpy matrix containing the stft of channel 1
+ symmetric_atn:
+ delay:
+ wmat (): a 2D Numpy matrix containing
+
+ Returns:
+ hist (np.array):
+ agrid:
+ dgrid:
+ """
- def make_histogram(self, stft_ch0, stft_ch1, wmat):
# What is going on here???
# ------------------------------------
# calculate the weighted histogram
p = 1
q = 0
- tfw = (np.abs(stft_ch0) * np.abs(stft_ch1)) ** p * (np.abs(wmat)) ** q # time-freq weights
+ tfw = (np.abs(self.stft_ch0) * np.abs(self.stft_ch1)) ** p * (np.abs(self.wmat)) ** q # time-freq weights
# only consider time-freq. points yielding estimates in bounds
- a_premask = np.logical_and(self.attenuation_min < alpha, alpha < self.attenuation_max)
- d_premask = np.logical_and(self.delay_min < delta, delta < self.delay_max)
+ a_premask = np.logical_and(self.attenuation_min < symmetric_atn, symmetric_atn < self.attenuation_max)
+ d_premask = np.logical_and(self.delay_min < delay, delay < self.delay_max)
ad_premask = np.logical_and(a_premask, d_premask)
ad_nzind = np.nonzero(ad_premask)
- alpha_vec = alpha[ad_nzind]
- delta_vec = delta[ad_nzind]
+ symmetric_atn_vec = symmetric_atn[ad_nzind]
+ delay_vec = delay[ad_nzind]
tfw_vec = tfw[ad_nzind]
# compute the histogram
- H = np.histogram2d(alpha_vec, delta_vec, bins=np.array([self.num_attenuation_bins, self.num_delay_bins]),
+ H = np.histogram2d(symmetric_atn_vec, delay_vec, bins=np.array([self.num_attenuation_bins, self.num_delay_bins]),
range=np.array([[self.attenuation_min, self.attenuation_max],
[self.delay_min, self.delay_max]]), normed=False,
weights=tfw_vec)
hist = H[0] / H[0].max()
- agrid = H[1]
- dgrid = H[2]
+ agrid = H[1] # attenuation bins
+ dgrid = H[2] # delay bins
# Save these for later
self.attenuation_grid = agrid
@@ -212,7 +223,10 @@ class Duet(separation_base.SeparationBase):
# normalize and plot the histogram
hist /= hist.max()
- return hist
+
+ return hist, agrid, dgrid
+
+
@staticmethod
def find_peaks2(data, min_thr=0.5, min_dist=None, max_peaks=1):
@@ -258,6 +272,27 @@ class Duet(separation_base.SeparationBase):
return peakIndex
+ def convert_peaks(self, agrid, dgrid):
+ """Receives the attenuation and delay bins and computes the delay/attenuation peaks based on the peak finder indices.
+
+ Parameters:
+ agrid:
+ dgrid:
+
+ Returns:
+ delay_peak:
+ atn_delay_est:
+ atnpeak:
+ """
+ symmetric_atn_peak = agrid[self.peak_indices[0, :]]
+ delay_peak = dgrid[self.peak_indices[1, :]]
+
+ atn_delay_est = np.vstack([symmetric_atn_peak, delay_peak]).T
+
+ # convert symmetric_atn to atnpeak
+ atnpeak = (symmetric_atn_peak + np.sqrt(symmetric_atn_peak ** 2 + 4)) / 2
+ return delay_peak, atn_delay_est, atnpeak
+
@staticmethod
def find_peaks(data, min_thr=0.5, min_dist=None, max_num=1):
# TODO: consolidate both find_peaks functions
@@ -301,6 +336,35 @@ class Duet(separation_base.SeparationBase):
return peak_indices
+ def compute_masks(self, atnpeak, delay_peak):
+ # compute masks for separation
+ bestsofar = np.inf * np.ones((self.num_frequency_bins - 1, self.num_time_bins))
+ bestind = np.zeros((self.num_frequency_bins - 1, self.num_time_bins), int)
+ for i in range(0, self.num_sources):
+ score = np.abs(atnpeak[i] * np.exp(-1j * self.wmat * delay_peak[i]) * self.stft_ch0 - self.stft_ch1) ** 2 / \
+ (1 + atnpeak[i] ** 2)
+ mask = (score < bestsofar)
+ bestind[mask] = i
+ bestsofar[mask] = score[mask]
+ return bestind, mask
+
+ def convert_time_domain(self, bestind, mask, atnpeak, delay_peak):
+ source_estimates = np.zeros((self.num_sources, self.audio_signal.signal_length))
+ for i in range(0, self.num_sources):
+ mask = (bestind == i)
+ Xm = np.vstack([np.zeros((1, self.num_time_bins)),
+ (self.stft_ch0 + atnpeak[i] * np.exp(1j * self.wmat * delay_peak[i]) * self.stft_ch1) /
+ (1 + atnpeak[i] ** 2) * mask])
+ # xi = spectral_utils.f_istft(Xm, L, winType, hop, fs)
+ xi = spectral_utils.e_istft(Xm, self.stft_params.window_length,
+ self.stft_params.hop_length, self.stft_params.window_type)
+
+ source_estimates[i, :] = utils.add_mismatched_arrays(source_estimates[i, ], xi)[:self.audio_signal.signal_length]
+ # add back to the separated signal a portion of the mixture to eliminate
+ # most of the masking artifacts
+ # source_estimates=source_estimates+0.05*x[0,:]
+ return source_estimates
+
@staticmethod
def _smooth_matrix(matrix, kernel):
"""Performs two-dimensional convolution in order to smooth the values of matrix elements.

change_type: ADD

diff:
+import os
+import Duet as dt
+import audio_signal
+
+def main():
+ # Load input file
+ input_file_name = os.path.join('..', 'Input', 'dev1_female3_inst_mix.wav')
+ signal = audio_signal.AudioSignal(path_to_input_file=input_file_name)
+
+ # make a directory to store output if needed
+ if not os.path.exists(os.path.join('..', 'Output/')):
+ os.mkdir(os.path.join('..', 'Output/'))
+
+ # Set up DUET
+ duet = dt.Duet(signal, num_sources=3)
+
+ # and run
+ duet.run()
+
+ # plot histogram results
+ duet.plot(os.path.join('..', 'Output', 'duet_2d.png'))
+ duet.plot(os.path.join('..', 'Output', 'duet_3d.png'), three_d_plot=True)
+
+ # Create output file for each source found
+ output_name_stem = os.path.join('..', 'Output', 'duet_source')
+ i = 1
+ for s in duet.make_audio_signals():
+ output_file_name = output_name_stem + str(i) + '.wav'
+ s.write_audio_to_file(output_file_name)
+ i += 1
+
+
+if __name__ == '__main__':
+ main()

diff:
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+from __future__ import division
+
+import unittest
+import nussl
+import numpy as np
+import scipy.io.wavfile as wav
+import os
+import warnings
+from nussl import Duet as dt
+
+
+class DuetUnitTests(unittest.TestCase):
+ input_file_name = os.path.join('..', 'Input', 'dev1_female3_inst_mix.wav')
+ signal = nussl.AudioSignal(path_to_input_file=input_file_name)
+
+ # def test_setup(self):
+ # input_file_name = os.path.join('..', 'Input', 'dev1_female3_inst_mix.wav')
+ # signal = nussl.AudioSignal(path_to_input_file=input_file_name)
+
+ # duet = nussl.Duet(signal, 3)
+ # duet.run()
+
+ def test_refact_duet(self):
+ refact_duet = dt.Duet(signal, num_sources=3)
+ refact_duet_result = refact_duet.run()
+ duet = nussl.Duet(signal, 3)
+ nussel_duet_result = duet.run()
+ assert refact_duet_result == nussel_duet_result
+
+
+
+ # def test_setup_duet(self):
+
+
+if __name__ == '__main__':
+ unittest.main()
+


message: Updated todos for Duet, no longer using MATLAB for benchmarks.

diff:
@@ -40,6 +40,9 @@ class Duet(separation_base.SeparationBase):
attenuation_min_distance (Optional[int]): Minimum distance between peaks wrt attenuation. Defaults to 5
delay_min_distance (Optional[int]): Minimum distance between peaks wrt delay. Defaults to 5
+ Attributes:
+
+
Examples:
:ref:`The DUET Demo Example <duet_demo>`
@@ -48,7 +51,7 @@ class Duet(separation_base.SeparationBase):
def __init__(self, input_audio_signal, num_sources,
attenuation_min=-3, attenuation_max=3, num_attenuation_bins=50,
delay_min=-3, delay_max=3, num_delay_bins=50,
- peak_threshold=0.2, attenuation_min_distance=5, delay_min_distance=5):
+ peak_threshold=0.2, attenuation_min_distance=5, delay_min_distance=5, p=1, q=0):
super(Duet, self).__init__(input_audio_signal=input_audio_signal)
if self.audio_signal.num_channels != 2:
@@ -72,14 +75,16 @@ class Duet(separation_base.SeparationBase):
self.non_normalized_hist = None
self.smoothed_hist = None
self.peak_indices = None
+ self.p = p
+ self.q = q
self.symmetric_atn = None
self.delay = None
self.num_frequency_bins = None
self.num_time_bins = None
self.stft_ch0 = None
- self.stft_ch = None
- self.wmat = None
+ self.stft_ch1 = None
+ self.frequency_matrix = None
def run(self):
"""Extracts N sources from a given stereo audio mixture (N sources captured via 2 sensors)
@@ -99,46 +104,54 @@ class Duet(separation_base.SeparationBase):
duet.run()
"""
+ if self.audio_signal.num_channels != 2: # double check this
+ raise ValueError('Cannot run Duet on audio signal without exactly 2 channels!')
- # Calculate the stft of both channels and create the frequency matrix
- self.stft_ch0, self.stft_ch1, self.wmat = self._compute_spectrogram(self.sample_rate)
+ # Calculate the stft of both channels and create the frequency matrix (the matrix containing the
+ # frequencies of analysis of the Fourier transform)
+ self.stft_ch0, self.stft_ch1, self.frequency_matrix = self._compute_spectrogram(self.sample_rate)
# Calculate the symmetric attenuation (alpha) and delay (delta) for each
# time-freq. point
- self.symmetric_atn, self.delay = self.compute_atn_delay()
+ self.symmetric_atn, self.delay = self._compute_atn_delay()
- # Make histogram and bins
- hist, agrid, dgrid = self.make_histogram()
+ # Make histogram of attenuation-delay values and get the center values for the bins in this histogram
+ hist, atn_bins, delay_bins = self.make_histogram(self.p, self.q)
+
+ # Find the location of peaks in the attenuation-delay plane
- # Find the location of peaks in the symmetric_atn-delay plane
self.peak_indices = self.find_peaks2(hist, self.peak_threshold,
np.array([self.attenuation_min_distance, self.delay_min_distance]),
self.num_sources)
+ peak_idxs_ = utils.find_peak_indices(hist, self.num_sources, threshold=self.peak_threshold)
+ # TODO: can we use this find_peaks()?
+ #Returns [1424, 1424, 1424] which doesn't make sense since hist is 50 by 50. find_peaks2 finds both the indices
+ #and the values as well.
+ # peak_idxs_ = utils.find_peak_indices(hist, self.num_sources, threshold=self.peak_threshold)
+ # peak_valsz_ = utils.find_peak_values(hist, self.num_sources, threshold=self.peak_threshold)
# compute delay_peak, attenuation peak, and attenuation/delay estimates
- delay_peak, atn_delay_est, atnpeak = self.convert_peaks(agrid, dgrid)
+ delay_peak, atn_delay_est, atn_peak = self.convert_peaks(atn_bins, delay_bins)
# compute masks for separation
- bestind, mask = self.compute_masks(atnpeak, delay_peak)
+ best_ind, mask = self.compute_masks(atn_peak, delay_peak)
# demix with ML alignment and convert to time domain
- source_estimates = self.convert_time_domain(bestind, mask, atnpeak, delay_peak)
+ source_estimates = self.convert_time_domain(best_ind, mask, atn_peak, delay_peak)
self.separated_sources = source_estimates
return source_estimates, atn_delay_est
- def _compute_spectrogram(self, fs):
+ def _compute_spectrogram(self, sample_rate):
""" Creates the stfts matrices for channel 0 and 1, and computes the frequency matrix.
Parameter:
- fs (integer): sample rate
+ sample_rate (integer): sample rate
Returns:
stft_ch0 (np.matrix): a 2D Numpy matrix containing the stft of channel 0
stft_ch1 (np.matrix): a 2D Numpy matrix containing the stft of channel 1
- wmat: a time frequency matrix
+ wmat (np.matrix): a 2D Numpy matrix containing the frequencies of analysis of the Fourier transform
"""
- if self.audio_signal.num_channels != 2: # double check this
- raise ValueError('Cannot run Duet on audio signal without exactly 2 channels!')
# Compute the stft of the two channel mixtures
self.audio_signal.stft_params = self.stft_params
@@ -150,26 +163,26 @@ class Duet(separation_base.SeparationBase):
time_vector = self.audio_signal.time_bins_vector
# remove dc component to avoid dividing by zero freq. in the delay estimation
- stft_ch0 = stft_ch0[1::, :]
+ stft_ch0 = stft_ch0[1:, :]
stft_ch1 = stft_ch1[1:, :]
self.num_frequency_bins = len(frequency_vector)
self.num_time_bins = len(time_vector)
# Compute the freq. matrix for later use in phase calculations
- wmat = np.array(np.tile(np.mat(frequency_vector[1:]).T, (1, self.num_time_bins))) * (2 * np.pi / fs) # WTF?
+ wmat = np.array(np.tile(np.mat(frequency_vector[1:]).T, (1, self.num_time_bins))) * (2 * np.pi / sample_rate)
return stft_ch0, stft_ch1, wmat
- def compute_atn_delay(self):
+ def _compute_atn_delay(self):
# Calculate the symmetric attenuation (alpha) and delay (delta) for each
# time-freq. point
- r21 = (self.stft_ch1 + constants.EPSILON) / (self.stft_ch0 + constants.EPSILON)
- atn = np.abs(r21) # relative attenuation between the two channels
+ inter_channel_ratio = (self.stft_ch1 + constants.EPSILON) / (self.stft_ch0 + constants.EPSILON)
+ atn = np.abs(inter_channel_ratio) # relative attenuation between the two channels
symmetric_atn = atn - 1 / atn # symmetric attenuation
- delay = -np.imag(np.log(r21)) / (2 * np.pi * self.wmat) # relative delay
+ delay = -np.imag(np.log(inter_channel_ratio)) / (2 * np.pi * self.frequency_matrix) # relative delay
return symmetric_atn, delay
- def make_histogram(self):
+ def make_histogram(self, p, q):
"""Receives the stft of the two channel mixtures and the frequency matrix to a create
a smooth and normalized histogram.
@@ -178,20 +191,16 @@ class Duet(separation_base.SeparationBase):
stft_ch1 (complex np.array): a 2D Numpy matrix containing the stft of channel 1
symmetric_atn (np.array): the symmetric attenuation between two channels
delay (np.array): the time delay between 2 channels
- wmat(np.array): a 2D Numpy matrix containing the time frequency matrix of the signal
+ wmat(np.array): a 2D Numpy matrix containing the frequency matrix of the signal
Returns:
hist (np.array): a smooth and normalized histogram
- agrid (np.array): attenuation bins
- dgrid (np.array): delay bins
+ atn_bins (np.array): attenuation bins
+ delay_bins (np.array): delay bins
"""
-
- # What is going on here???
- # ------------------------------------
# calculate the weighted histogram
- p = 1
- q = 0
- tfw = (np.abs(self.stft_ch0) * np.abs(self.stft_ch1)) ** p * (np.abs(self.wmat)) ** q # time-freq weights
+ time_frequency_weights = (np.abs(self.stft_ch0) * np.abs(self.stft_ch1)) ** p \
+ * (np.abs(self.frequency_matrix)) ** q
# only consider time-freq. points yielding estimates in bounds
a_premask = np.logical_and(self.attenuation_min < self.symmetric_atn, self.symmetric_atn < self.attenuation_max)
@@ -201,32 +210,33 @@ class Duet(separation_base.SeparationBase):
ad_nzind = np.nonzero(ad_premask)
symmetric_atn_vec = self.symmetric_atn[ad_nzind]
delay_vec = self.delay[ad_nzind]
- tfw_vec = tfw[ad_nzind]
+ tfw_vec = time_frequency_weights[ad_nzind]
# compute the histogram
- H = np.histogram2d(symmetric_atn_vec, delay_vec, bins=np.array([self.num_attenuation_bins, self.num_delay_bins]),
+ hist, atn_bins, delay_bins = np.histogram2d(symmetric_atn_vec, delay_vec,
+ bins=np.array([self.num_attenuation_bins, self.num_delay_bins]),
range=np.array([[self.attenuation_min, self.attenuation_max],
[self.delay_min, self.delay_max]]), normed=False,
weights=tfw_vec)
- hist = H[0] / H[0].max()
- agrid = H[1] # attenuation bins
- dgrid = H[2] # delay bins
-
# Save these for later
- self.attenuation_grid = agrid
- self.delay_grid = dgrid
- self.attenuation_delay_histogram = hist
- self.non_normalized_hist = H[0]
+ self.attenuation_grid = atn_bins
+ self.delay_grid = delay_bins
+
+ # TODO: do these operations happen twice?
+ # resolved
+ self.attenuation_delay_histogram = hist / hist.max()
+ self.non_normalized_hist = hist
+ # save smoothed_hist (not normalized) as an option for plotting
self.smoothed_hist = self._smooth_matrix(self.non_normalized_hist, np.array([3]))
- # smooth the histogram - local average 3-by-3 neighboring bins
- hist = self._smooth_matrix(hist, np.array([3]))
+ # smooth the normalized histogram - local average 3-by-3 neighboring bins
+ hist = self._smooth_matrix(self.attenuation_delay_histogram, np.array([3]))
# normalize and plot the histogram
hist /= hist.max()
- return hist, agrid, dgrid
+ return hist, atn_bins, delay_bins
@staticmethod
def find_peaks2(data, min_thr=0.5, min_dist=None, max_peaks=1):
@@ -245,6 +255,7 @@ class Duet(separation_base.SeparationBase):
"""
assert (type(data) == np.ndarray)
+ # noinspection PyPep8Naming
Rdata, Cdata = data.shape
if min_dist is None:
min_dist = np.array([np.floor(Rdata / 4), np.floor(Cdata / 4)])
@@ -272,26 +283,33 @@ class Duet(separation_base.SeparationBase):
return peakIndex
- def convert_peaks(self, agrid, dgrid):
+ def convert_peaks(self, atn_bins, delay_bins):
"""Receives the attenuation and delay bins and computes the delay/attenuation peaks based on the peak finder indices.
Parameters:
- agrid (np.array): Attenuation bins
- dgrid (np.array): Delay bins
+ atn_bins (np.array): Attenuation bins
+ delay_bins (np.array): Delay bins
Returns:
- delay_peak:
- atn_delay_est:
- atnpeak:
+ delay_peak(np.array): The delay peaks determined from the histogram
+ atn_delay_est (np.array): The estimated symmetric attenuation and delay values
+ atn_peak (np.array): Attenuation converted from symmetric attenuation
"""
- symmetric_atn_peak = agrid[self.peak_indices[0, :]]
- delay_peak = dgrid[self.peak_indices[1, :]]
+ # TODO:
+ if self.peak_indices is None:
+ raise ValueError('')
+
+ if any(a > len(atn_bins) for a in self.peak_indices[0, :]):
+ raise ValueError('Cant ')
+
+ symmetric_atn_peak = atn_bins[self.peak_indices[0, :]]
+ delay_peak = delay_bins[self.peak_indices[1, :]]
atn_delay_est = np.vstack([symmetric_atn_peak, delay_peak]).T
- # convert symmetric_atn to atnpeak
- atnpeak = (symmetric_atn_peak + np.sqrt(symmetric_atn_peak ** 2 + 4)) / 2
- return delay_peak, atn_delay_est, atnpeak
+ # convert symmetric_atn to atn_peak
+ atn_peak = (symmetric_atn_peak + np.sqrt(symmetric_atn_peak ** 2 + 4)) / 2
+ return delay_peak, atn_delay_est, atn_peak
@staticmethod
def find_peaks(data, min_thr=0.5, min_dist=None, max_num=1):
@@ -336,25 +354,51 @@ class Duet(separation_base.SeparationBase):
return peak_indices
- def compute_masks(self, atnpeak, delay_peak):
+ def compute_masks(self, atn_peak, delay_peak):
+ """Receives the attenuation and delay peaks and computes a mask to be applied to the signal for source
+ separation.
+
+ Parameters:
+ atn_peak (np.array): Attenuation peaks determined from histogram
+ delay_peak (np.array): Delay peaks determined from histogram
+ Returns:
+ best_ind(np.array): The indices for where the masks are applied
+ mask (np.array): A binary mask used to separate the sources
+
+ """
# compute masks for separation
- bestsofar = np.inf * np.ones((self.num_frequency_bins - 1, self.num_time_bins))
- bestind = np.zeros((self.num_frequency_bins - 1, self.num_time_bins), int)
+ best_so_far = np.inf * np.ones((self.num_frequency_bins - 1, self.num_time_bins))
+ best_ind = np.zeros((self.num_frequency_bins - 1, self.num_time_bins), dtype=int)
+ mask = None
+
for i in range(0, self.num_sources):
- score = np.abs(atnpeak[i] * np.exp(-1j * self.wmat * delay_peak[i]) * self.stft_ch0 - self.stft_ch1) ** 2 / \
- (1 + atnpeak[i] ** 2)
- mask = (score < bestsofar)
- bestind[mask] = i
- bestsofar[mask] = score[mask]
- return bestind, mask
-
- def convert_time_domain(self, bestind, mask, atnpeak, delay_peak):
+ phase = np.exp(-1j * self.frequency_matrix * delay_peak[i])
+ score = np.abs(atn_peak[i] * phase * self.stft_ch0 - self.stft_ch1) ** 2 / (1 + atn_peak[i] ** 2)
+ mask = (score < best_so_far)
+ best_ind[mask] = i
+ best_so_far[mask] = score[mask]
+
+ return best_ind, mask
+
+ def convert_time_domain(self, best_ind, mask, atn_peak, delay_peak):
+ """Receives the attenuation and delay peaks, the mask and best indices and applies the mask to separate the sources
+
+ Parameters:
+ best_ind (np.array): The indices for where the masks are applied
+ mask (np.array): binary mask used to separate the sources
+ atn_peak (np.array): Attenuation peaks determined from histogram
+ delay_peak (np.array): Delay peaks determined from histogram
+
+ Returns:
+ source_estimates (np.array): The arrays of the separated source signals
+
+ """
source_estimates = np.zeros((self.num_sources, self.audio_signal.signal_length))
for i in range(0, self.num_sources):
- mask = (bestind == i)
+ mask = (best_ind == i)
Xm = np.vstack([np.zeros((1, self.num_time_bins)),
- (self.stft_ch0 + atnpeak[i] * np.exp(1j * self.wmat * delay_peak[i]) * self.stft_ch1) /
- (1 + atnpeak[i] ** 2) * mask])
+ (self.stft_ch0 + atn_peak[i] * np.exp(1j * self.frequency_matrix * delay_peak[i]) * self.stft_ch1) /
+ (1 + atn_peak[i] ** 2) * mask])
# xi = spectral_utils.f_istft(Xm, L, winType, hop, fs)
xi = spectral_utils.e_istft(Xm, self.stft_params.window_length,
self.stft_params.hop_length, self.stft_params.window_type)
@@ -402,7 +446,7 @@ class Duet(separation_base.SeparationBase):
copy_row = int(np.floor(krow / 2)) # number of rows to copy on top and bottom
copy_col = int(np.floor(kcol / 2)) # number of columns to copy on either side
- # TODO: This is very ugly. Make this readable
+ # TODO: This is very ugly. Make this readable, write issue on Github
# form the augmented matrix (rows and columns added to top, bottom, and sides)
matrix = np.mat(matrix) # make sure Mat is a Numpy matrix
augMat = np.vstack(

diff:
@@ -89,16 +89,19 @@ def find_peak_indices(input_array, n_peaks, min_dist=None, do_min=False, thresho
peak_indices = []
for i in range(n_peaks):
- cur_peak_idx = np.argmax(input_array)
+ # np.unravel_index for 2D indices e.g., index 5 in a 3x3 array should be (1, 2)
+ # Also, wrap in tuple for duck typing
+ cur_peak_idx = tuple(np.unravel_index(np.argmax(input_array), input_array.shape))
peak_indices.append(cur_peak_idx)
# zero out peak and its surroundings
if is_1d:
+ cur_peak_idx = cur_peak_idx[0]
lower, upper = _set_array_zero_indices(cur_peak_idx, zero_dist, len(input_array))
input_array[lower:upper] = 0
else:
- lower0, upper0 = _set_array_zero_indices(cur_peak_idx, zero_dist0, input_array.shape[0])
- lower1, upper1 = _set_array_zero_indices(cur_peak_idx, zero_dist1, input_array.shape[1])
+ lower0, upper0 = _set_array_zero_indices(cur_peak_idx[0], zero_dist0, input_array.shape[0])
+ lower1, upper1 = _set_array_zero_indices(cur_peak_idx[1], zero_dist1, input_array.shape[1])
input_array[lower0:upper0, lower1:upper1] = 0
if np.sum(input_array) == 0.0:

diff:
@@ -86,7 +86,9 @@ else
for i = 1:n
for j = 1:m
Xij = X((1:win1)+i-1,(1:win2)+j-1); % Sliding window of size win
- [val,row,col] = maxi(Xij);
+ [val, idx] = max(Xij(:));
+ [row, col] = ind2sub(size(Xij),idx);
+
if all([row,col] == [v1+1,v2+1]) && val >= thresh % If maximum local & above threshold, it is a peak
P = cat(1,P,val);
I = cat(1,I,i);

diff:
@@ -25,12 +25,11 @@ x2 = x(:,2);
%wlen = 1024; timestep = 512; numfreq = 1024; ovp = 0;
% ->
-wlen = 2048; timestep = 1024; numfreq = 2048;
-% <-
-awin = hamming(wlen); % analysis window is a Hamming window
+wlen = 1024; overlap = 0; numfreq = 1024;
+% <-awin = hamming(wlen); % analysis window is a Hamming window
-[tf1,Fout1,Tout1,Pout1] = f_stft(x1,wlen,'hamming',timestep,numfreq,fs);
-[tf2,Fout2,Tout2,Pout2] = f_stft(x2,wlen,'hamming',timestep,numfreq,fs);
+[tf1,Fout1,Tout1,Pout1] = f_stft(x1,wlen,'rectangular',overlap,numfreq,fs);
+[tf2,Fout2,Tout2,Pout2] = f_stft(x2,wlen,'rectangular',overlap,numfreq,fs);
tf1(1,:) = []; tf2(1,:) = []; % remove dc component from mixtures to avoid dividing by zero frequency in the delay estimation
save('tf1.mat', 'tf1'); save('tf2.mat', 'tf2');
freq_len = length(Fout1);
@@ -133,7 +132,7 @@ for i=1:numsources
esti = tfsynthesis([zeros(1,size(tf1,2));
((tf1+peaka(i)*exp(sqrt(-1)*fmat*peakdelta(i)).*tf2)...
./(1+peaka(i)^2)).*mask],...
- sqrt(2)*awin/wlen,timestep,numfreq);
+ sqrt(2)*awin/wlen,overlap,numfreq);
est(i,:)=esti(1:length(x1))';
% add back into the demix a little bit of the mixture
% as that eliminates most of the masking artifacts

diff:
-990a2b178b6c289dce7842d08289d911d79ea1cb
\ No newline at end of file
+810643d0ba5676777b365423318e2b864e8010d3
\ No newline at end of file

diff:
-364e273cadb28468615500e8bd9f14263bcd6267
\ No newline at end of file
+49d3c61b3bd4606d66fcf27c03124e53b2d28285
\ No newline at end of file

diff:
@@ -22,14 +22,14 @@ class DuetUnitTests(unittest.TestCase):
# duet = nussl.Duet(signal, 3)
# duet.run()
- # def test_refact_duet(self):
- # input_file_name = os.path.join('..', 'input', 'dev1_female3_inst_mix.wav')
- # signal = nussl.AudioSignal(path_to_input_file=input_file_name)
- # refact_duet = nussl.Duet(signal, num_sources=3)
- # refact_duet_result = refact_duet.run()
- # duet = nussl.Duet(signal, 3)
- # nussel_duet_result = duet.run()
- # assert refact_duet_result == nussel_duet_result
+ def test_refact_duet(self):
+ input_file_name = os.path.join('..', 'input', 'dev1_female3_inst_mix.wav')
+ signal = nussl.AudioSignal(path_to_input_file=input_file_name)
+ refact_duet = nussl.Duet(signal, num_sources=3)
+ refact_duet_result = refact_duet.run()
+ duet = nussl.Duet(signal, 3)
+ nussel_duet_result = duet.run()
+ assert refact_duet_result == nussel_duet_result
@staticmethod
def _load_matlab_results():
@@ -49,7 +49,7 @@ class DuetUnitTests(unittest.TestCase):
signal = nussl.AudioSignal(audio_data_array=np_sin)
with self.assertRaises(ValueError):
duet = nussl.Duet(signal, 3)
- duet.compute_spectrogram(duet.sample_rate)
+ duet._compute_spectrogram(duet.sample_rate)
def test_compute_spectrogram_wmat(self):
# Load MATLAB values
@@ -64,12 +64,14 @@ class DuetUnitTests(unittest.TestCase):
path = os.path.join('..', 'Input', 'dev1_female3_inst_mix.wav')
signal = nussl.AudioSignal(path)
duet = nussl.Duet(signal, 3)
- duet_sft0, duet_sft1, duet_wmat = duet.compute_spectrogram(duet.sample_rate)
- zero_check = duet_sft0 - tf1_mat
- max_error = np.max(zero_check)
- assert np.allclose(duet_sft0, tf1_mat, atol=1e-02) #Still has the first and last col doubled
- assert np.allclose(duet_sft1, tf2_mat)
- assert np.allclose(duet_wmat, fmat)
+ duet.stft_params.window_length = 1024
+ duet.stft_params.window_type = nussl.WINDOW_RECTANGULAR
+ duet.stft_params.hop_length = duet.stft_params.window_length
+
+ duet_sft0, duet_sft1, duet_wmat = duet._compute_spectrogram(duet.sample_rate)
+ assert np.allclose(duet_sft0, tf1_mat, atol=1e-06)
+ assert np.allclose(duet_sft1, tf2_mat, atol=1e-06)
+ # assert np.allclose(duet_wmat, fmat)
# def test_compute_atn_delay(self):
# sym_atn_mat_path = os.path.join('duet_reference', 'rickard_duet', 'alpha_duet')

diff:
@@ -18,6 +18,19 @@ class TestUtils(unittest.TestCase):
min_idx = int(np.pi * 100)
triangle = np.abs(signal.sawtooth(np.arange(0, 10, 0.01)))
+ arr = np.arange(0, 100)
+ peak = nussl.find_peak_indices(arr, 1)
+ assert peak == 99
+
+ arr = np.arange(0, 100).reshape(10, 10)
+ peak = nussl.find_peak_indices(arr, 1)
+ assert peak == (9, 9)
+
+ np.random.seed(0)
+ arr = np.random.randint(0, 100, size=(100, 100))
+
+
+
def test_add_mismatched_arrays(self):
long_array = np.ones((20,))
short_array = np.arange(10)


message: Changed to utils peak finder and starting unit tests using development branch.

diff:
@@ -73,7 +73,6 @@ class Duet(separation_base.SeparationBase):
self.attenuation_delay_histogram = None
self.non_normalized_hist = None
- self.smoothed_hist = None
self.peak_indices = None
self.p = p
self.q = q
@@ -120,16 +119,13 @@ class Duet(separation_base.SeparationBase):
# Find the location of peaks in the attenuation-delay plane
- self.peak_indices = self.find_peaks2(hist, self.peak_threshold,
- np.array([self.attenuation_min_distance, self.delay_min_distance]),
- self.num_sources)
- peak_idxs_ = utils.find_peak_indices(hist, self.num_sources, threshold=self.peak_threshold)
+ # self.peak_indices = self.find_peaks2(hist, self.peak_threshold,
+ # np.array([self.attenuation_min_distance, self.delay_min_distance]),
+ # self.num_sources)
+
+ self.peak_indices = utils.find_peak_indices(hist, self.num_sources, threshold=self.peak_threshold,
+ min_dist=[self.attenuation_min_distance, self.delay_min_distance])
- # TODO: can we use this find_peaks()?
- #Returns [1424, 1424, 1424] which doesn't make sense since hist is 50 by 50. find_peaks2 finds both the indices
- #and the values as well.
- # peak_idxs_ = utils.find_peak_indices(hist, self.num_sources, threshold=self.peak_threshold)
- # peak_valsz_ = utils.find_peak_values(hist, self.num_sources, threshold=self.peak_threshold)
# compute delay_peak, attenuation peak, and attenuation/delay estimates
delay_peak, atn_delay_est, atn_peak = self.convert_peaks(atn_bins, delay_bins)
@@ -227,8 +223,6 @@ class Duet(separation_base.SeparationBase):
# resolved
self.attenuation_delay_histogram = hist / hist.max()
self.non_normalized_hist = hist
- # save smoothed_hist (not normalized) as an option for plotting
- self.smoothed_hist = self._smooth_matrix(self.non_normalized_hist, np.array([3]))
# smooth the normalized histogram - local average 3-by-3 neighboring bins
hist = self._smooth_matrix(self.attenuation_delay_histogram, np.array([3]))
@@ -297,15 +291,18 @@ class Duet(separation_base.SeparationBase):
"""
# TODO:
if self.peak_indices is None:
- raise ValueError('')
+ raise ValueError('No peak indices')
+
+ atn_indices = [x[0] for x in self.peak_indices]
+ delay_indices = [x[1] for x in self.peak_indices]
- if any(a > len(atn_bins) for a in self.peak_indices[0, :]):
- raise ValueError('Cant ')
+ if any(a > len(atn_bins) for a in atn_indices):
+ raise ValueError('Attenuation index greater than length of bins')
- symmetric_atn_peak = atn_bins[self.peak_indices[0, :]]
- delay_peak = delay_bins[self.peak_indices[1, :]]
+ symmetric_atn_peak = atn_bins[atn_indices]
+ delay_peak = delay_bins[delay_indices]
- atn_delay_est = np.vstack([symmetric_atn_peak, delay_peak]).T
+ atn_delay_est = np.column_stack((symmetric_atn_peak, delay_peak))
# convert symmetric_atn to atn_peak
atn_peak = (symmetric_atn_peak + np.sqrt(symmetric_atn_peak ** 2 + 4)) / 2
@@ -500,7 +497,10 @@ class Duet(separation_base.SeparationBase):
AA = np.tile(self.attenuation_grid[1::], (self.num_delay_bins, 1)).T
DD = np.tile(self.delay_grid[1::].T, (self.num_attenuation_bins, 1))
- histogram_data = self.attenuation_delay_histogram if normalize else self.smoothed_hist
+ # save smoothed_hist (not normalized) as an option for plotting
+ smoothed_hist = self._smooth_matrix(self.non_normalized_hist, np.array([3]))
+
+ histogram_data = self.attenuation_delay_histogram if normalize else smoothed_hist
# plot the histogram in 2D
if not three_d_plot:

diff:
@@ -87,6 +87,8 @@ def find_peak_indices(input_array, n_peaks, min_dist=None, do_min=False, thresho
if np.size(np.nonzero(input_array)) < n_peaks:
warnings.warn('Threshold set such that there will be less peaks than n_peaks.')
+ input_array = np.multiply(input_array, (input_array >= threshold))
+
peak_indices = []
for i in range(n_peaks):
# np.unravel_index for 2D indices e.g., index 5 in a 3x3 array should be (1, 2)

diff:
@@ -22,7 +22,7 @@ class DuetUnitTests(unittest.TestCase):
# duet = nussl.Duet(signal, 3)
# duet.run()
- def test_refact_duet(self):
+ def test_duet_outputs(self):
input_file_name = os.path.join('..', 'input', 'dev1_female3_inst_mix.wav')
signal = nussl.AudioSignal(path_to_input_file=input_file_name)
refact_duet = nussl.Duet(signal, num_sources=3)
@@ -78,19 +78,16 @@ class DuetUnitTests(unittest.TestCase):
# delay_mat_path = os.path.join('duet_reference', 'rickard_duet', 'delta_duet')
# sym_atn_mat = scipy.io.loadmat(sym_atn_mat_path)['sym'].T
# delay_mat = scipy.io.loadmat(delay_mat_path)['delay'].T
- #
# def test_make_histogram(self):
- # def test_find_peaks2(self):
+ # def test_convert_peaks
- # def test_convert_peaks(self):
+ # def test_compute_masks
- # def test_compute_masks(self):
+ # def test_convert_time_domain
- # def test_convert_time_domain(self):
-
- # def test_setup_duet(self):
+ # test_smooth_matrix
if __name__ == '__main__':

diff:
@@ -26,10 +26,6 @@ class TestUtils(unittest.TestCase):
peak = nussl.find_peak_indices(arr, 1)
assert peak == (9, 9)
- np.random.seed(0)
- arr = np.random.randint(0, 100, size=(100, 100))
-
-
def test_add_mismatched_arrays(self):
long_array = np.ones((20,))


message: Added duet_benchmarks folder for unit test values and saved MATLAB tests for later.

diff:
+b8961c51100c8e3ccdba191febfd3c5a0c29b7c9
\ No newline at end of file

diff:
+2bf76ec3b3b56bae442bad5e3a01a8c6a71aea1f
\ No newline at end of file

diff:
+42996955d5e42a9b7d858c532ff6299c596dd565
\ No newline at end of file

diff:
+bdb5a75d2ffc4ad3e95b98bd776560560177d805
\ No newline at end of file

diff:
+f8fb481cc282f9c762c8fa40a2514d9c7982e403
\ No newline at end of file

diff:
@@ -22,25 +22,25 @@ class DuetUnitTests(unittest.TestCase):
# duet = nussl.Duet(signal, 3)
# duet.run()
- def test_duet_outputs(self):
- input_file_name = os.path.join('..', 'input', 'dev1_female3_inst_mix.wav')
- signal = nussl.AudioSignal(path_to_input_file=input_file_name)
- refact_duet = nussl.Duet(signal, num_sources=3)
- refact_duet_result = refact_duet.run()
- duet = nussl.Duet(signal, 3)
- nussel_duet_result = duet.run()
- assert refact_duet_result == nussel_duet_result
-
- @staticmethod
- def _load_matlab_results():
-
- f_mat_path = os.path.join('duet_reference', 'rickard_duet', 'fmat')
- tf1_path = os.path.join('duet_reference', 'rickard_duet', 'tf1')
- tf2_path = os.path.join('duet_reference', 'rickard_duet', 'tf2')
-
- fmat = scipy.io.loadmat(f_mat_path)['back'].T
- delay_mat = scipy.io.loadmat(delay_mat_path)['fore'].T
- return sym_atn_mat, delay_mat
+ # def test_duet_outputs(self):
+ # input_file_name = os.path.join('..', 'input', 'dev1_female3_inst_mix.wav')
+ # signal = nussl.AudioSignal(path_to_input_file=input_file_name)
+ # refact_duet = nussl.Duet(signal, num_sources=3)
+ # refact_duet_result = refact_duet.run()
+ # duet = nussl.Duet(signal, 3)
+ # nussel_duet_result = duet.run()
+ # assert refact_duet_result == nussel_duet_result
+ #
+ # @staticmethod
+ # def _load_matlab_results():
+ #
+ # f_mat_path = os.path.join('duet_reference', 'rickard_duet', 'fmat')
+ # tf1_path = os.path.join('duet_reference', 'rickard_duet', 'tf1')
+ # tf2_path = os.path.join('duet_reference', 'rickard_duet', 'tf2')
+ #
+ # fmat = scipy.io.loadmat(f_mat_path)['back'].T
+ # delay_mat = scipy.io.loadmat(delay_mat_path)['fore'].T
+ # return sym_atn_mat, delay_mat
def test_compute_spectrogram_1_channel(self):
# Test with one channel, should throw value error
@@ -54,23 +54,23 @@ class DuetUnitTests(unittest.TestCase):
def test_compute_spectrogram_wmat(self):
# Load MATLAB values
# f_mat_path = os.path.join('duet_reference', 'rickard_duet', 'fmat')
- tf1_path = os.path.join('duet_reference', 'rickard_duet', 'tf1')
- tf2_path = os.path.join('duet_reference', 'rickard_duet', 'tf2')
+ stft0_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch0.npy')
+ stft1_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch1.npy')
# fmat = scipy.io.loadmat(f_mat_path)['fmat']
- tf1_mat = scipy.io.loadmat(tf1_path)['tf1']
- tf2_mat = scipy.io.loadmat(tf2_path)['tf2']
+ benchmark_stft0 = np.load(stft0_path)
+ benchmark_stft1 = np.load(stft1_path)
path = os.path.join('..', 'Input', 'dev1_female3_inst_mix.wav')
signal = nussl.AudioSignal(path)
duet = nussl.Duet(signal, 3)
- duet.stft_params.window_length = 1024
- duet.stft_params.window_type = nussl.WINDOW_RECTANGULAR
- duet.stft_params.hop_length = duet.stft_params.window_length
+ # duet.stft_params.window_length = 1024
+ # duet.stft_params.window_type = nussl.WINDOW_RECTANGULAR
+ # duet.stft_params.hop_length = duet.stft_params.window_length
duet_sft0, duet_sft1, duet_wmat = duet._compute_spectrogram(duet.sample_rate)
- assert np.allclose(duet_sft0, tf1_mat, atol=1e-06)
- assert np.allclose(duet_sft1, tf2_mat, atol=1e-06)
+ assert np.all(benchmark_stft0 == duet_sft0)
+ assert np.all(benchmark_stft0 == duet_sft1)
# assert np.allclose(duet_wmat, fmat)
# def test_compute_atn_delay(self):

diff:
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+from __future__ import division
+
+import unittest
+import nussl
+import numpy as np
+import scipy.io.wavfile as wav
+import scipy.io
+import os
+import warnings
+
+
+# import sys
+# sys.path.insert(1, 'C:\\Users\\danielfelixkim\\Documents\\GitHub\\InteractiveAudioLab\\nussl\\nussl')
+
+class DuetUnitTests(unittest.TestCase):
+ # def test_setup(self):
+ # input_file_name = os.path.join('..', 'Input', 'dev1_female3_inst_mix.wav')
+ # signal = nussl.AudioSignal(path_to_input_file=input_file_name)
+
+ # duet = nussl.Duet(signal, 3)
+ # duet.run()
+
+ def test_duet_outputs(self):
+ input_file_name = os.path.join('..', 'input', 'dev1_female3_inst_mix.wav')
+ signal = nussl.AudioSignal(path_to_input_file=input_file_name)
+ refact_duet = nussl.Duet(signal, num_sources=3)
+ refact_duet_result = refact_duet.run()
+ duet = nussl.Duet(signal, 3)
+ nussel_duet_result = duet.run()
+ assert refact_duet_result == nussel_duet_result
+
+ @staticmethod
+ def _load_matlab_results():
+ f_mat_path = os.path.join('duet_reference', 'rickard_duet', 'fmat')
+ tf1_path = os.path.join('duet_reference', 'rickard_duet', 'tf1')
+ tf2_path = os.path.join('duet_reference', 'rickard_duet', 'tf2')
+
+ fmat = scipy.io.loadmat(f_mat_path)['back'].T
+ delay_mat = scipy.io.loadmat(delay_mat_path)['fore'].T
+ return sym_atn_mat, delay_mat
+
+ def test_compute_spectrogram_1_channel(self):
+ # Test with one channel, should throw value error
+ num_samples = 100 # 1 second
+ np_sin = np.sin(np.linspace(0, 100 * 2 * np.pi, num_samples)) # Freq = 100 Hz
+ signal = nussl.AudioSignal(audio_data_array=np_sin)
+ with self.assertRaises(ValueError):
+ duet = nussl.Duet(signal, 3)
+ duet._compute_spectrogram(duet.sample_rate)
+
+ def test_compute_spectrogram_wmat(self):
+ # Load MATLAB values
+ # f_mat_path = os.path.join('duet_reference', 'rickard_duet', 'fmat')
+ tf1_path = os.path.join('duet_reference', 'rickard_duet', 'tf1')
+ tf2_path = os.path.join('duet_reference', 'rickard_duet', 'tf2')
+
+ # fmat = scipy.io.loadmat(f_mat_path)['fmat']
+ tf1_mat = scipy.io.loadmat(tf1_path)['tf1']
+ tf2_mat = scipy.io.loadmat(tf2_path)['tf2']
+
+ path = os.path.join('..', 'Input', 'dev1_female3_inst_mix.wav')
+ signal = nussl.AudioSignal(path)
+ duet = nussl.Duet(signal, 3)
+ duet.stft_params.window_length = 1024
+ duet.stft_params.window_type = nussl.WINDOW_RECTANGULAR
+ duet.stft_params.hop_length = duet.stft_params.window_length
+
+ duet_sft0, duet_sft1, duet_wmat = duet._compute_spectrogram(duet.sample_rate)
+ assert np.allclose(duet_sft0, tf1_mat, atol=1e-06)
+ assert np.allclose(duet_sft1, tf2_mat, atol=1e-06)
+ # assert np.allclose(duet_wmat, fmat)
+
+ # def test_compute_atn_delay(self):
+ # sym_atn_mat_path = os.path.join('duet_reference', 'rickard_duet', 'alpha_duet')
+ # delay_mat_path = os.path.join('duet_reference', 'rickard_duet', 'delta_duet')
+ # sym_atn_mat = scipy.io.loadmat(sym_atn_mat_path)['sym'].T
+ # delay_mat = scipy.io.loadmat(delay_mat_path)['delay'].T
+
+ # def test_make_histogram(self):
+
+ # def test_convert_peaks
+
+ # def test_compute_masks
+
+ # def test_convert_time_domain
+
+ # test_smooth_matrix
+
+
+if __name__ == '__main__':
+ unittest.main()
+


message: Added additional unit tests for Duet benchmarking.

diff:
@@ -17,7 +17,6 @@ def main():
# and run
duet.run()
- print duet.stft_ch0
# plot histogram results
duet.plot(os.path.join('..', 'Output', 'duet_2d.png'))
duet.plot(os.path.join('..', 'Output', 'duet_3d.png'), three_d_plot=True)

change_type: DELETE

diff:
-b8961c51100c8e3ccdba191febfd3c5a0c29b7c9
\ No newline at end of file

diff:
-2bf76ec3b3b56bae442bad5e3a01a8c6a71aea1f
\ No newline at end of file
+6d0d15e720bf359d444fd0a3e4b2a10c312ab7cd
\ No newline at end of file

diff:
-42996955d5e42a9b7d858c532ff6299c596dd565
\ No newline at end of file
+224318577eceffd14466c12dfe4121ceca3ca218
\ No newline at end of file

diff:
-bdb5a75d2ffc4ad3e95b98bd776560560177d805
\ No newline at end of file

diff:
@@ -10,37 +10,24 @@ import scipy.io
import os
import warnings
-# import sys
-# sys.path.insert(1, 'C:\\Users\\danielfelixkim\\Documents\\GitHub\\InteractiveAudioLab\\nussl\\nussl')
class DuetUnitTests(unittest.TestCase):
-
- # def test_setup(self):
- # input_file_name = os.path.join('..', 'Input', 'dev1_female3_inst_mix.wav')
- # signal = nussl.AudioSignal(path_to_input_file=input_file_name)
-
- # duet = nussl.Duet(signal, 3)
- # duet.run()
-
- # def test_duet_outputs(self):
- # input_file_name = os.path.join('..', 'input', 'dev1_female3_inst_mix.wav')
- # signal = nussl.AudioSignal(path_to_input_file=input_file_name)
- # refact_duet = nussl.Duet(signal, num_sources=3)
- # refact_duet_result = refact_duet.run()
- # duet = nussl.Duet(signal, 3)
- # nussel_duet_result = duet.run()
- # assert refact_duet_result == nussel_duet_result
- #
- # @staticmethod
- # def _load_matlab_results():
- #
- # f_mat_path = os.path.join('duet_reference', 'rickard_duet', 'fmat')
- # tf1_path = os.path.join('duet_reference', 'rickard_duet', 'tf1')
- # tf2_path = os.path.join('duet_reference', 'rickard_duet', 'tf2')
+ def setUp(self):
+ # Use the same audio file that the benchmarks were run with
+ path = os.path.join('..', 'Input', 'dev1_female3_inst_mix.wav')
+ signal = nussl.AudioSignal(path)
+ self.duet = nussl.Duet(signal, 3)
+
+ # def test_duet_final_outputs(self):
+ # #Test final outputs
+ # source_estimates_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_source_estimates.npy')
+ # atn_delay_est_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_atn_delay_est.npy')
+ # benchmark_source_estimates = np.load(source_estimates_path)
+ # benchmark_atn_delay_est = np.load(atn_delay_est_path)
#
- # fmat = scipy.io.loadmat(f_mat_path)['back'].T
- # delay_mat = scipy.io.loadmat(delay_mat_path)['fore'].T
- # return sym_atn_mat, delay_mat
+ # duet_source_estimates, duet_atn_delay_est = self.duet.run()
+ # assert benchmark_source_estimates == duet_source_estimates
+ # assert benchmark_atn_delay_est == duet_atn_delay_est
def test_compute_spectrogram_1_channel(self):
# Test with one channel, should throw value error
@@ -52,34 +39,56 @@ class DuetUnitTests(unittest.TestCase):
duet._compute_spectrogram(duet.sample_rate)
def test_compute_spectrogram_wmat(self):
- # Load MATLAB values
- # f_mat_path = os.path.join('duet_reference', 'rickard_duet', 'fmat')
+ # Load Duet values to benchmark against
stft0_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch0.npy')
stft1_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch1.npy')
+ wmat_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_wmat.npy')
- # fmat = scipy.io.loadmat(f_mat_path)['fmat']
- benchmark_stft0 = np.load(stft0_path)
- benchmark_stft1 = np.load(stft1_path)
+ benchmark_stft_ch0 = np.load(stft0_path)
+ benchmark_stft_ch1 = np.load(stft1_path)
+ benchmark_wmat = np.load(wmat_path)
- path = os.path.join('..', 'Input', 'dev1_female3_inst_mix.wav')
- signal = nussl.AudioSignal(path)
- duet = nussl.Duet(signal, 3)
- # duet.stft_params.window_length = 1024
- # duet.stft_params.window_type = nussl.WINDOW_RECTANGULAR
- # duet.stft_params.hop_length = duet.stft_params.window_length
-
- duet_sft0, duet_sft1, duet_wmat = duet._compute_spectrogram(duet.sample_rate)
- assert np.all(benchmark_stft0 == duet_sft0)
- assert np.all(benchmark_stft0 == duet_sft1)
- # assert np.allclose(duet_wmat, fmat)
-
- # def test_compute_atn_delay(self):
- # sym_atn_mat_path = os.path.join('duet_reference', 'rickard_duet', 'alpha_duet')
- # delay_mat_path = os.path.join('duet_reference', 'rickard_duet', 'delta_duet')
- # sym_atn_mat = scipy.io.loadmat(sym_atn_mat_path)['sym'].T
- # delay_mat = scipy.io.loadmat(delay_mat_path)['delay'].T
-
- # def test_make_histogram(self):
+ duet_sft0, duet_sft1, duet_wmat = self.duet._compute_spectrogram(self.duet.sample_rate)
+ assert np.all(benchmark_stft_ch0 == duet_sft0)
+ assert np.all(benchmark_stft_ch1 == duet_sft1)
+ assert np.all(benchmark_wmat == duet_wmat)
+
+ def test_compute_atn_delay(self):
+ sym_atn_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch0.npy')
+ delay_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch0.npy')
+ benchmark_sym_atn = np.load(sym_atn_path)
+ benchmark_delay = np.load(delay_path)
+
+ symmetric_atn, delay = self.duet._compute_atn_delay()
+
+ assert np.all(benchmark_sym_atn == symmetric_atn)
+ assert np.all(benchmark_delay == delay)
+
+ def test_make_histogram(self):
+ #Load benchmarks
+ hist_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_hist.npy')
+ atn_bins_path = os.path.join('duet_reference', 'duet_benchmarks', 'atn_bins.npy')
+ delay_bins_path = os.path.join('duet_reference', 'duet_benchmarks', 'delay_bins.npy')
+ benchmark_hist = np.load(hist_path)
+ benchmark_atn_bins = np.load(atn_bins_path)
+ benchmark_delay_bins = np.load(delay_bins_path)
+
+ hist, atn_bins, delay_bins = self.duet.make_histogram(self.duet.p, self.duet.q)
+
+ assert np.all(benchmark_hist == hist)
+ assert np.all(benchmark_atn_bins == atn_bins)
+ assert np.all(benchmark_delay_bins == delay_bins)
+
+ def test_peak_indices(self):
+ hist_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_hist.npy')
+ peak_indices_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_peak_indices.npy')
+ benchmark_hist = np.load(hist_path)
+ benchmark_peak_indices = np.load(peak_indices_path)
+
+ duet_peak_indices = nussl.utils.find_peak_indices(benchmark_hist, self.duet.num_sources, threshold=self.duet.peak_threshold,
+ min_dist=[self.duet.attenuation_min_distance, self.duet.delay_min_distance])
+
+ assert np.all(benchmark_peak_indices == duet_peak_indices)
# def test_convert_peaks


message: Confirmed that the first 3 tests worked, need to debug histogram and reformat tests.

diff:
+fb06e141efcbf878f10e2e87e0c5dd3f7371b47d
\ No newline at end of file

diff:
+e3ee0d75ab4abed4ba9d9a37c6275bd95711f837
\ No newline at end of file

diff:
@@ -54,8 +54,17 @@ class DuetUnitTests(unittest.TestCase):
assert np.all(benchmark_wmat == duet_wmat)
def test_compute_atn_delay(self):
- sym_atn_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch0.npy')
- delay_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch0.npy')
+ #Use the same stfts for comparing this function's outputs
+ stft0_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch0.npy')
+ stft1_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch1.npy')
+ wmat_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_wmat.npy')
+ self.duet.stft_ch0 = np.load(stft0_path)
+ self.duet.stft_ch1 = np.load(stft1_path)
+ self.duet.frequency_matrix = np.load(wmat_path)
+
+ #Load benchmarks
+ sym_atn_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_sym_atn.npy')
+ delay_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_delay.npy')
benchmark_sym_atn = np.load(sym_atn_path)
benchmark_delay = np.load(delay_path)
@@ -64,31 +73,43 @@ class DuetUnitTests(unittest.TestCase):
assert np.all(benchmark_sym_atn == symmetric_atn)
assert np.all(benchmark_delay == delay)
- def test_make_histogram(self):
- #Load benchmarks
- hist_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_hist.npy')
- atn_bins_path = os.path.join('duet_reference', 'duet_benchmarks', 'atn_bins.npy')
- delay_bins_path = os.path.join('duet_reference', 'duet_benchmarks', 'delay_bins.npy')
- benchmark_hist = np.load(hist_path)
- benchmark_atn_bins = np.load(atn_bins_path)
- benchmark_delay_bins = np.load(delay_bins_path)
-
- hist, atn_bins, delay_bins = self.duet.make_histogram(self.duet.p, self.duet.q)
-
- assert np.all(benchmark_hist == hist)
- assert np.all(benchmark_atn_bins == atn_bins)
- assert np.all(benchmark_delay_bins == delay_bins)
-
- def test_peak_indices(self):
- hist_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_hist.npy')
- peak_indices_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_peak_indices.npy')
- benchmark_hist = np.load(hist_path)
- benchmark_peak_indices = np.load(peak_indices_path)
-
- duet_peak_indices = nussl.utils.find_peak_indices(benchmark_hist, self.duet.num_sources, threshold=self.duet.peak_threshold,
- min_dist=[self.duet.attenuation_min_distance, self.duet.delay_min_distance])
-
- assert np.all(benchmark_peak_indices == duet_peak_indices)
+ # def test_make_histogram(self):
+ # #Use the same stfts for comparing this function's outputs
+ # stft0_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch0.npy')
+ # stft1_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch1.npy')
+ # wmat_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_wmat.npy')
+ # sym_atn_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_sym_atn.npy')
+ # delay_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_delay.npy')
+ # self.duet.stft_ch0 = np.load(stft0_path)
+ # self.duet.stft_ch1 = np.load(stft1_path)
+ # self.duet.frequency_matrix = np.load(wmat_path)
+ # self.symmetric_atn = np.load(sym_atn_path)
+ # self.delay = np.load(delay_path)
+ #
+ # #Load benchmarks
+ # hist_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_hist.npy')
+ # atn_bins_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_atn_bins.npy')
+ # delay_bins_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_delay_bins.npy')
+ # benchmark_hist = np.load(hist_path)
+ # benchmark_atn_bins = np.load(atn_bins_path)
+ # benchmark_delay_bins = np.load(delay_bins_path)
+ #
+ # hist, atn_bins, delay_bins = self.duet.make_histogram(self.duet.p, self.duet.q)
+ #
+ # assert np.all(benchmark_hist == hist)
+ # assert np.all(benchmark_atn_bins == atn_bins)
+ # assert np.all(benchmark_delay_bins == delay_bins)
+ #
+ # def test_peak_indices(self):
+ # hist_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_hist.npy')
+ # peak_indices_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_peak_indices.npy')
+ # benchmark_hist = np.load(hist_path)
+ # benchmark_peak_indices = np.load(peak_indices_path)
+ #
+ # duet_peak_indices = nussl.utils.find_peak_indices(benchmark_hist, self.duet.num_sources, threshold=self.duet.peak_threshold,
+ # min_dist=[self.duet.attenuation_min_distance, self.duet.delay_min_distance])
+ #
+ # assert np.all(benchmark_peak_indices == duet_peak_indices)
# def test_convert_peaks


message: Added updated Duet tests, transformer NMF and demo for it.

diff:
+import time
+import numpy as np
+import nussl
+
+import nimfa
+
+def simple_example():
+ """
+ A simple example of NMF in nussl
+ """
+ # Make two simple matrices
+ n = 4
+ a = np.arange(n ** 2).reshape((n, n))
+ b = 2 * a + 3
+
+ # Mix them together
+ mixture = np.dot(b, a)
+
+ # Set up NU NMF
+ n_bases = 2
+ n_iter = 100
+ nussl_nmf = nussl.TransformerNMF(mixture, n_bases)
+ nussl_nmf.should_use_epsilon = False
+ nussl_nmf.max_num_iterations = n_iter
+ nussl_nmf.distance_measure = nussl.DistanceType.DIVERGENCE
+
+ # run NU NMF
+ nussl_nmf.run()
+
+ signals = nussl_nmf.recombine_calculated_matrices()
+ # for sig in signals:
+ # print sig
+
+ V = mixture
+ nimfa_nmf = nimfa.Nmf(V, max_iter=n_iter, rank=n_bases, update='divergence')
+ nmf_fit = nimfa_nmf()
+ W = nmf_fit.basis()
+ H = nmf_fit.coef()
+
+ nimfa_est = np.dot(W, H)
+ nussl_est = np.dot(nussl_nmf.templates, nussl_nmf.activation_matrix)
+ error = np.abs(nussl_est - nimfa_est) / nimfa_est * 100
+
+ print('nimfa estimate:\n%s\n\n' % nimfa_est)
+ print('nussl estimate:\n%s\n\n' % nussl_est)
+ print('Errors:\n%s' % error)
+
+ sm = nmf_fit.summary()
+ # print( np.dot(W, H))
+
+ x = 1
+ y = 2
+ z = x + y
+
+if __name__ == '__main__':
+ simple_example()

diff:
@@ -26,7 +26,6 @@ class NMF(separation_base.SeparationBase):
def __str__(self):
return "Nmf"
- # TODO: Change this so that NMF accepts an AudioSignal object and not a raw stft
def __init__(self, input_audio_signal, num_templates,
activation_matrix=None, templates=None, distance_measure=None,
should_update_template=None, should_update_activation=None):

diff:
@@ -9,6 +9,7 @@ from .audio_signal import AudioSignal
from separation_base import SeparationBase
from Duet import Duet
from Nmf import NMF, DistanceType
+from transformer_nmf import TransformerNMF, DistanceType
from repet import Repet
from repet_sim import RepetSim
from ft2d import FT2D

diff:
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import random
+import math
+import numpy as np
+
+import constants
+
+class TransformerNMF(object):
+ def __init__(self, input_matrix, num_templates,
+ activation_matrix=None, templates=None, distance_measure=None,
+ should_update_template=None, should_update_activation=None):
+
+ if num_templates <= 0:
+ raise Exception('Need more than 0 bases!')
+
+ self.input_matrix = input_matrix
+ self.num_templates = num_templates
+
+ if self.input_matrix.size <= 0:
+ raise Exception('Input matrix size must be > 0!')
+
+ if np.iscomplexobj(input_matrix):
+ raise Exception('Input matrix must be real')
+
+ if np.min(input_matrix) < 0.0:
+ raise Exception('Input matrix must be nonnegative!')
+
+ self.activation_matrix = None
+ self.templates = None
+
+ if activation_matrix is None and templates is None:
+ self.templates = np.zeros((self.input_matrix.shape[0], num_templates)) # W, in literature
+ self.activation_matrix = np.zeros((num_templates, self.input_matrix.shape[1])) # H, in literature
+ self.randomize_input_matrices()
+ elif activation_matrix is not None and templates is not None:
+ self.templates = templates
+ self.activation_matrix = activation_matrix
+ else:
+ raise Exception('Must provide both activation matrix and template vectors or nothing at all!')
+
+ self.distance_measure = distance_measure if distance_measure is not None else DistanceType.DEFAULT
+ self.should_update_template = True if should_update_template is None else should_update_template
+ self.should_update_activation = True if should_update_activation is None else should_update_activation
+
+ self.should_use_epsilon = False # Replace this with something more general
+ self.epsilon_euclidean_type = True
+ self.stopping_epsilon = 1e10
+ self.max_num_iterations = 20
+
+ self.reconstruction_error = []
+
+ def run(self):
+ """
+ This runs the NMF separation algorithm. This function assumes that all
+ parameters have been set prior to running.
+
+ No inputs. N must be set prior to calling this function.
+
+ Returns an activation matrix (in a 2d numpy array)
+ and a set of template vectors (also 2d numpy array).
+ """
+
+ if self.input_matrix is None or self.input_matrix.size == 0:
+ raise Exception('Cannot do NMF with an empty input_matrix!')
+
+ if self.num_templates is None or self.num_templates == 0:
+ raise Exception('Cannot do NMF with no bases!')
+
+ if self.should_use_epsilon:
+ print('Warning: User is expected to have set stopping_epsilon prior to using'
+ ' this function. Expect this to take a long time if you have not set'
+ ' a suitable epsilon.')
+
+ should_stop = False
+ num_iterations = 0
+ while not should_stop:
+
+ self.update()
+
+ self.reconstruction_error.append(self._euclidean_distance() if self.epsilon_euclidean_type else
+ self._divergence())
+
+ # Stopping conditions
+ num_iterations += 1
+ if self.should_use_epsilon:
+ if self.epsilon_euclidean_type:
+ should_stop = self._euclidean_distance() <= self.stopping_epsilon
+ else:
+ should_stop = self._divergence() <= self.stopping_epsilon
+ else:
+ should_stop = num_iterations >= self.max_num_iterations
+
+ return self.activation_matrix, self.templates
+
+ def update(self):
+ """
+ Computes a single update using the update function specified.
+ :return: nothing
+ """
+ # update activation matrix
+ if self.should_update_activation:
+ if self.distance_measure == DistanceType.EUCLIDEAN:
+ self.activation_matrix = self._update_activation_euclidean()
+
+ elif self.distance_measure == DistanceType.DIVERGENCE:
+ self.activation_matrix = self._update_activation_divergent()
+
+ # update template vectors
+ if self.should_update_template:
+ if self.distance_measure == DistanceType.EUCLIDEAN:
+ self.templates = self._update_template_euclidean()
+
+ elif self.distance_measure == DistanceType.DIVERGENCE:
+ self.templates = self._update_template_divergence()
+
+ def _update_activation_euclidean(self):
+ # make a new matrix to store results
+ activation_copy = np.empty_like(self.activation_matrix)
+
+ # store in memory so we don't have to do n*m calculations.
+ template_T = self.templates.T
+ temp_T_matrix = np.dot(template_T, self.input_matrix)
+ temp_T_act = np.dot(np.dot(template_T, self.templates), self.activation_matrix)
+
+ # Eq. 4, H update from [1]
+ for indices, val in np.ndenumerate(self.activation_matrix):
+ result = temp_T_matrix[indices]
+ result /= temp_T_act[indices]
+ result *= self.activation_matrix[indices]
+ activation_copy[indices] = result
+
+ return activation_copy
+
+ def _update_template_euclidean(self):
+ # make a new matrix to store results
+ template_copy = np.empty_like(self.templates)
+
+ # store in memory so we don't have to do n*m calculations.
+ activation_T = self.activation_matrix.T
+ input_matrix_act_T = np.dot(self.input_matrix, activation_T)
+ temp_act = np.dot(np.dot(self.templates, self.activation_matrix), activation_T)
+
+ # Eq. 4, W update from [1]
+ for indices, val in np.ndenumerate(self.templates):
+ result = input_matrix_act_T[indices]
+ result /= temp_act[indices]
+ result *= self.templates[indices]
+ template_copy[indices] = result
+
+ return template_copy
+
+ def _update_activation_divergent(self):
+ # make a new matrix to store results
+ activation_copy = np.empty_like(self.activation_matrix)
+
+ dot = np.dot(self.templates, self.activation_matrix)
+
+ # Eq. 5, H update from [1]
+ for indices, val in np.ndenumerate(self.activation_matrix):
+ (a, mu) = indices
+ result = sum((self.templates[i][a] * self.input_matrix[i][mu]) / dot[i][mu]
+ for i in range(self.templates.shape[0]))
+ result /= sum(self.templates[k][a] for k in range(self.templates.shape[0]))
+ result *= self.activation_matrix[indices]
+ activation_copy[indices] = result
+
+ return activation_copy
+
+ def _update_template_divergence(self):
+ # make a new matrix to store results
+ template_copy = np.empty_like(self.templates)
+
+ dot = np.dot(self.templates, self.activation_matrix)
+
+ # Eq. 5, W update from [1]
+ for indices, val in np.ndenumerate(self.templates):
+ (i, a) = indices
+ result = sum((self.activation_matrix[a][mu] * self.input_matrix[i][mu]) / dot[i][mu]
+ for mu in range(self.activation_matrix.shape[1]))
+ result /= sum(self.activation_matrix[a][nu] for nu in range(self.activation_matrix.shape[1]))
+ result *= self.templates[indices]
+ template_copy[indices] = result
+
+ return template_copy
+
+ def _euclidean_distance(self):
+ try:
+ mixture = np.dot(self.templates, self.activation_matrix)
+ except:
+ print(self.activation_matrix.shape, self.templates.shape)
+ return
+
+ if mixture.shape != self.input_matrix.shape:
+ raise Exception('Something went wrong! Recombining the activation matrix '
+ 'and template vectors is not the same size as the input matrix!')
+
+ return sum((self.input_matrix[index] - val) ** 2 for index, val in np.ndenumerate(mixture))
+
+ def _divergence(self):
+ mixture = np.dot(self.activation_matrix, self.templates)
+
+ if mixture.shape != self.input_matrix.shape:
+ raise Exception('Something went wrong! Recombining the activation matrix '
+ 'and template vectors is not the same size as the input matrix!')
+
+ return sum(
+ (self.input_matrix[index] * math.log(self.input_matrix[index] / val, 10) + self.input_matrix[index] - val)
+ for index, val in np.ndenumerate(mixture))
+
+ def recombine_calculated_matrices(self):
+ new_matrices = []
+ for n in range(self.num_templates):
+ matrix = np.empty_like(self.activation_matrix)
+ matrix[n,] = self.activation_matrix[n,]
+
+ new_matrix = np.dot(self.templates, matrix)
+ new_matrices.append(new_matrix)
+ return new_matrices
+
+ def randomize_input_matrices(self, shouldNormalize=False):
+ self._randomize_matrix(self.activation_matrix, shouldNormalize)
+ self._randomize_matrix(self.templates, shouldNormalize)
+
+ @staticmethod
+ def _randomize_matrix(M, shouldNormalize=False):
+ for i, row in enumerate(M):
+ for j, col in enumerate(row):
+ M[i][j] = random.random()
+
+ if not shouldNormalize:
+ M[i][j] *= constants.DEFAULT_MAX_VAL
+ return M
+
+ def plot(self, outputFile, **kwargs):
+ raise NotImplementedError('Sorry, you cannot do this yet.')
+
+class DistanceType:
+ EUCLIDEAN = 'euclidean'
+ DIVERGENCE = 'divergence'
+ DEFAULT = EUCLIDEAN
+
+ def __init__(self):
+ pass
\ No newline at end of file

diff:
@@ -10,13 +10,24 @@ import scipy.io
import os
import warnings
-
class DuetUnitTests(unittest.TestCase):
+
def setUp(self):
- # Use the same audio file that the benchmarks were run with
path = os.path.join('..', 'Input', 'dev1_female3_inst_mix.wav')
- signal = nussl.AudioSignal(path)
- self.duet = nussl.Duet(signal, 3)
+ self.signal = nussl.AudioSignal(path)
+ #Call benchmarks
+ self.duet = nussl.Duet(self.signal, 3)
+ self.benchmark_dict = self.load_benchmarks()
+
+ def load_benchmarks(self):
+ benchmark_dict = {}
+ directory = 'duet_reference/duet_benchmarks'
+ for filename in os.listdir(directory):
+ key = os.path.splitext(filename)[0]
+ file_path = os.path.join('duet_reference', 'duet_benchmarks', filename)
+ value = np.load(file_path)
+ benchmark_dict[key] = value
+ return benchmark_dict
# def test_duet_final_outputs(self):
# #Test final outputs
@@ -40,78 +51,75 @@ class DuetUnitTests(unittest.TestCase):
def test_compute_spectrogram_wmat(self):
# Load Duet values to benchmark against
- stft0_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch0.npy')
- stft1_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch1.npy')
- wmat_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_wmat.npy')
-
- benchmark_stft_ch0 = np.load(stft0_path)
- benchmark_stft_ch1 = np.load(stft1_path)
- benchmark_wmat = np.load(wmat_path)
+ duet = nussl.Duet(self.signal, 3)
+ duet_sft0, duet_sft1, duet_wmat = duet._compute_spectrogram(self.duet.sample_rate)
+ assert np.all(np.array(self.benchmark_dict['benchmark_stft_ch0']) == duet_sft0)
+ assert np.all(np.array(self.benchmark_dict['benchmark_stft_ch1']) == duet_sft1)
+ assert np.all(np.array(self.benchmark_dict['benchmark_wmat']) == duet_wmat)
- duet_sft0, duet_sft1, duet_wmat = self.duet._compute_spectrogram(self.duet.sample_rate)
- assert np.all(benchmark_stft_ch0 == duet_sft0)
- assert np.all(benchmark_stft_ch1 == duet_sft1)
- assert np.all(benchmark_wmat == duet_wmat)
def test_compute_atn_delay(self):
+ #Use the same stfts for comparing the two functions' outputs
+ duet = nussl.Duet(self.signal, 3)
+ duet.stft_ch0 = self.benchmark_dict['benchmark_stft_ch0']
+ duet.stft_ch1 = self.benchmark_dict['benchmark_stft_ch1']
+ duet.frequency_matrix = self.benchmark_dict['benchmark_wmat']
+
+ symmetric_atn, delay = duet._compute_atn_delay()
+
+ assert np.all(np.array(self.benchmark_dict['benchmark_sym_atn'])== symmetric_atn)
+ assert np.all(np.array(self.benchmark_dict['benchmark_delay'])== delay)
+
+ def test_make_histogram(self):
#Use the same stfts for comparing this function's outputs
- stft0_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch0.npy')
- stft1_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch1.npy')
- wmat_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_wmat.npy')
- self.duet.stft_ch0 = np.load(stft0_path)
- self.duet.stft_ch1 = np.load(stft1_path)
- self.duet.frequency_matrix = np.load(wmat_path)
+ duet = nussl.Duet(self.signal, 3)
+ duet.stft_ch0 = self.benchmark_dict['benchmark_stft_ch0']
+ duet.stft_ch1 = self.benchmark_dict['benchmark_stft_ch1']
+ duet.frequency_matrix = self.benchmark_dict['benchmark_wmat']
+ duet.symmetric_atn = self.benchmark_dict['benchmark_sym_atn']
+ duet.delay = self.benchmark_dict['benchmark_delay']
#Load benchmarks
- sym_atn_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_sym_atn.npy')
- delay_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_delay.npy')
- benchmark_sym_atn = np.load(sym_atn_path)
- benchmark_delay = np.load(delay_path)
-
- symmetric_atn, delay = self.duet._compute_atn_delay()
-
- assert np.all(benchmark_sym_atn == symmetric_atn)
- assert np.all(benchmark_delay == delay)
-
- # def test_make_histogram(self):
- # #Use the same stfts for comparing this function's outputs
- # stft0_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch0.npy')
- # stft1_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_stft_ch1.npy')
- # wmat_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_wmat.npy')
- # sym_atn_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_sym_atn.npy')
- # delay_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_delay.npy')
- # self.duet.stft_ch0 = np.load(stft0_path)
- # self.duet.stft_ch1 = np.load(stft1_path)
- # self.duet.frequency_matrix = np.load(wmat_path)
- # self.symmetric_atn = np.load(sym_atn_path)
- # self.delay = np.load(delay_path)
- #
- # #Load benchmarks
- # hist_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_hist.npy')
- # atn_bins_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_atn_bins.npy')
- # delay_bins_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_delay_bins.npy')
- # benchmark_hist = np.load(hist_path)
- # benchmark_atn_bins = np.load(atn_bins_path)
- # benchmark_delay_bins = np.load(delay_bins_path)
- #
- # hist, atn_bins, delay_bins = self.duet.make_histogram(self.duet.p, self.duet.q)
- #
- # assert np.all(benchmark_hist == hist)
- # assert np.all(benchmark_atn_bins == atn_bins)
- # assert np.all(benchmark_delay_bins == delay_bins)
- #
- # def test_peak_indices(self):
- # hist_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_hist.npy')
- # peak_indices_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_peak_indices.npy')
- # benchmark_hist = np.load(hist_path)
- # benchmark_peak_indices = np.load(peak_indices_path)
- #
- # duet_peak_indices = nussl.utils.find_peak_indices(benchmark_hist, self.duet.num_sources, threshold=self.duet.peak_threshold,
- # min_dist=[self.duet.attenuation_min_distance, self.duet.delay_min_distance])
- #
- # assert np.all(benchmark_peak_indices == duet_peak_indices)
+ hist_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_hist.npy')
+ atn_bins_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_atn_bins.npy')
+ delay_bins_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_delay_bins.npy')
+ benchmark_hist = np.load(hist_path)
+ benchmark_atn_bins = np.load(atn_bins_path)
+ benchmark_delay_bins = np.load(delay_bins_path)
+
+ hist, atn_bins, delay_bins = duet.make_histogram(duet.p, duet.q)
+
+ assert np.all(benchmark_hist == hist)
+ assert np.all(benchmark_atn_bins == atn_bins)
+ assert np.all(benchmark_delay_bins == delay_bins)
+
+ def test_peak_indices(self):
+ duet = nussl.Duet(self.signal, 3)
+ duet.stft_ch0 = self.benchmark_dict['benchmark_stft_ch0']
+ duet.stft_ch1 = self.benchmark_dict['benchmark_stft_ch1']
+ duet.frequency_matrix = self.benchmark_dict['benchmark_wmat']
+ duet.symmetric_atn = self.benchmark_dict['benchmark_sym_atn']
+ duet.delay = self.benchmark_dict['benchmark_delay']
+
+ hist_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_hist.npy')
+ peak_indices_path = os.path.join('duet_reference', 'duet_benchmarks', 'benchmark_peak_indices.npy')
+ benchmark_hist = np.load(hist_path)
+ benchmark_peak_indices = np.load(peak_indices_path)
+
+ duet_peak_indices = nussl.utils.find_peak_indices(benchmark_hist, self.duet.num_sources, threshold=self.duet.peak_threshold,
+ min_dist=[self.duet.attenuation_min_distance, self.duet.delay_min_distance])
+
+ # original DUET returned peaks as [[28 21 44] [24 25 24]] instead of [(28, 24), (21,25), (44,24)]
+ # Convert current peaks being tested to original format
+ atn_indices = [x[0] for x in duet_peak_indices]
+ delay_indices = [x[1] for x in duet_peak_indices]
+ duet_peak_indices = np.row_stack((atn_indices, delay_indices))
+
+ assert np.all(benchmark_peak_indices == duet_peak_indices)
+
+ def test_convert_peaks(self):
+ pass
- # def test_convert_peaks
# def test_compute_masks
@@ -119,6 +127,7 @@ class DuetUnitTests(unittest.TestCase):
# test_smooth_matrix
+ #TODO: fix this function before writing test for it
if __name__ == '__main__':
unittest.main()