http://www.perlmonks.org?node_id=969305


in reply to SAPI and Win32::OLE's broken WithEvents

A couple of comments on the code.

First, in Events, you have a massive if/elsif/.../else. And every item is checking the same thing - the event name. This looks like a perfect use for given/when:

given ($hash{'eventName'}) { when ('AudioLevel') {...} ... }
Except that you're doing the same thing in each clause (except for the default/unknown case). So a hash of arrays would likely work simpler:
my %keys = ( AudioLevel => [qw(StreamNumber StreamPosition AudioLevel)], Phoneme => [qw(StreamNumber StreamPosition Duration NextPhoneId F +eature CurrentPhoneId)], # ... ); if ($keys{$hash{'eventName'}}) { @hash{@{$keys{$hash{'eventName'}}}} = @_[2..$#_]; } else { die "unknown event $hash{'eventName'}"; }
I think that'll produce more concise and, more importantly, more readable code. Of course, it's missing important bits where you call other functions, and this is definitely solvable (especially with anonymous code refs in your %keys hash, assuming that the assignment code here looks for them and calls them). You may prefer given/when as it's less of a change from how you're currently thinking, but I generally prefer code refs.
my %keys = ( ... Viseme => [ qw(StreamNumber StreamPosition Duration), { NextVisemeId => sub { DecodeSpeechVisemeType($_[5]) }, Feature => sub { DecodeSpeechVisemeFeature($_[6]) }, CurrentVisemeId => sub { DecodeSpeechVisemeType($_[7]) } ], ... ); if ($keys{$hash{'eventName'}}) { my @keys = @{$keys{$hash{'eventName'}}}; my $dynamic_keys = ref $keys[-1] ? pop @keys : {}; @hash{@keys} = @_[2..$#keys+2]; for my $dyn (keys %$dynamic_keys) { $hash{$dyn} = $dyanmic_keys->{$dyn}->(@_); } } else { die "unknown event $hash{'eventName'}"; }
I don't think that's too bad. A bit more difficult than if nothing was dynamic, but that's kind of the price you pay for that dynamicism.

Second is your @table for the DecodeSpeechVisemeType function. You may be better off putting the @table inside your function and calling it a state variable instead of a my. You can still initialise it once this way, but gets rid of some extra braces. But it also means that you need to learn to initialise arrays as part of their declaration. Instead of my @table; $table[0] =..., say my @table = ( 'silence', 'ae ax ah', ... );. I'm actually surprised what you have is working, because my understanding is that your initialisation for @table wouldn't be called until after the Win32::OLE->MessageLoop() returns.

Finally, DecodeSpeechVisemeFeature - again with the if/elsif/else. Use a lookup hash. Or, in this case, a lookup array.

Warning: all code above untested. :-)

Replies are listed 'Best First'.
Re^2: SAPI and Win32::OLE's broken WithEvents
by bulk88 (Priest) on May 07, 2012 at 19:46 UTC
    I'm actually surprised what you have is working, because my understanding is that your initialisation for @table wouldn't be called until after the Win32::OLE->MessageLoop() returns.

    Your right about @table. Its broken, in the output its all undef. I failed at the closure. Should have put a BEGIN block around it.

    @hash{@{$keys{$hash{'eventName'}}}} = @_2..$#_;

    "@hash{" what is that? hash is a % or a $ for slices.