├── a.wav
├── README.md
├── noiseReduction
├── noiseReduction.xcodeproj
│ ├── xcuserdata
│ │ ├── LJP.xcuserdatad
│ │ │ ├── xcdebugger
│ │ │ │ └── Breakpoints_v2.xcbkptlist
│ │ │ └── xcschemes
│ │ │ │ └── xcschememanagement.plist
│ │ └── dengsir.xcuserdatad
│ │ │ └── xcschemes
│ │ │ └── xcschememanagement.plist
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ ├── xcuserdata
│ │ │ ├── LJP.xcuserdatad
│ │ │ │ └── UserInterfaceState.xcuserstate
│ │ │ └── dengsir.xcuserdatad
│ │ │ │ └── UserInterfaceState.xcuserstate
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── project.pbxproj
├── noiseReduction
│ ├── ViewController.h
│ ├── AppDelegate.h
│ ├── main.m
│ ├── Info.plist
│ ├── SDK
│ │ ├── timing.h
│ │ ├── noise_suppression.h
│ │ └── noise_suppression.c
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── AppDelegate.m
│ └── ViewController.m
├── noiseReductionTests
│ ├── Info.plist
│ └── noiseReductionTests.m
└── noiseReductionUITests
│ ├── Info.plist
│ └── noiseReductionUITests.m
└── .gitignore
/a.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lijingpei2016/noiseReduction/HEAD/a.wav
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # noiseReduction
2 | 基于WebRTC实现iOS端音频降噪功能
3 |
4 | 使用方法:
5 | 配置好路径就ok
6 | NSString * inpath = @“/ Users / apple / Desktop / a.wav;
7 | NSString *outpath = @"/Users/apple/Desktop/b.wav";
8 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction.xcodeproj/xcuserdata/LJP.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction.xcodeproj/project.xcworkspace/xcuserdata/LJP.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lijingpei2016/noiseReduction/HEAD/noiseReduction/noiseReduction.xcodeproj/project.xcworkspace/xcuserdata/LJP.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction.xcodeproj/project.xcworkspace/xcuserdata/dengsir.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lijingpei2016/noiseReduction/HEAD/noiseReduction/noiseReduction.xcodeproj/project.xcworkspace/xcuserdata/dengsir.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // noiseReduction
4 | //
5 | // Created by LJP on 2018/8/23.
6 | // Copyright © 2018 LJP. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // noiseReduction
4 | //
5 | // Created by LJP on 2018/8/23.
6 | // Copyright © 2018 LJP. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // noiseReduction
4 | //
5 | // Created by LJP on 2018/8/23.
6 | // Copyright © 2018 LJP. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction.xcodeproj/xcuserdata/LJP.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | noiseReduction.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction.xcodeproj/xcuserdata/dengsir.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | noiseReduction.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReductionTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReductionUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReductionTests/noiseReductionTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // noiseReductionTests.m
3 | // noiseReductionTests
4 | //
5 | // Created by LJP on 2018/8/23.
6 | // Copyright © 2018 LJP. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface noiseReductionTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation noiseReductionTests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 | // Put setup code here. This method is called before the invocation of each test method in the class.
20 | }
21 |
22 | - (void)tearDown {
23 | // Put teardown code here. This method is called after the invocation of each test method in the class.
24 | [super tearDown];
25 | }
26 |
27 | - (void)testExample {
28 | // This is an example of a functional test case.
29 | // Use XCTAssert and related functions to verify your tests produce the correct results.
30 | }
31 |
32 | - (void)testPerformanceExample {
33 | // This is an example of a performance test case.
34 | [self measureBlock:^{
35 | // Put the code you want to measure the time of here.
36 | }];
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReductionUITests/noiseReductionUITests.m:
--------------------------------------------------------------------------------
1 | //
2 | // noiseReductionUITests.m
3 | // noiseReductionUITests
4 | //
5 | // Created by LJP on 2018/8/23.
6 | // Copyright © 2018 LJP. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface noiseReductionUITests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation noiseReductionUITests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 |
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 |
22 | // In UI tests it is usually best to stop immediately when a failure occurs.
23 | self.continueAfterFailure = NO;
24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
25 | [[[XCUIApplication alloc] init] launch];
26 |
27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
28 | }
29 |
30 | - (void)tearDown {
31 | // Put teardown code here. This method is called after the invocation of each test method in the class.
32 | [super tearDown];
33 | }
34 |
35 | - (void)testExample {
36 | // Use recording to get started writing UI tests.
37 | // Use XCTAssert and related functions to verify your tests produce the correct results.
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | # CocoaPods
32 | #
33 | # We recommend against adding the Pods directory to your .gitignore. However
34 | # you should judge for yourself, the pros and cons are mentioned at:
35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
36 | #
37 | # Pods/
38 |
39 | # Carthage
40 | #
41 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
42 | # Carthage/Checkouts
43 |
44 | Carthage/Build
45 |
46 | # fastlane
47 | #
48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
49 | # screenshots whenever they are needed.
50 | # For more information about the recommended setup visit:
51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
52 |
53 | fastlane/report.xml
54 | fastlane/Preview.html
55 | fastlane/screenshots/**/*.png
56 | fastlane/test_output
57 |
58 | # Code Injection
59 | #
60 | # After new code Injection tools there's a generated folder /iOSInjectionProject
61 | # https://github.com/johnno1962/injectionforxcode
62 |
63 | iOSInjectionProject/
64 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction/SDK/timing.h:
--------------------------------------------------------------------------------
1 |
2 | #include
3 |
4 | #if defined(__APPLE__)
5 | # include
6 | #elif defined(_WIN32)
7 | # define WIN32_LEAN_AND_MEAN
8 |
9 | # include
10 |
11 | #else // __linux
12 |
13 | # include
14 |
15 | # ifndef CLOCK_MONOTONIC //_RAW
16 | # define CLOCK_MONOTONIC CLOCK_REALTIME
17 | # endif
18 | #endif
19 |
20 | static
21 | uint64_t nanotimer() {
22 | static int ever = 0;
23 | #if defined(__APPLE__)
24 | static mach_timebase_info_data_t frequency;
25 | if (!ever) {
26 | if (mach_timebase_info(&frequency) != KERN_SUCCESS) {
27 | return 0;
28 | }
29 | ever = 1;
30 | }
31 | return (mach_absolute_time() * frequency.numer / frequency.denom);
32 | #elif defined(_WIN32)
33 | static LARGE_INTEGER frequency;
34 | if (!ever) {
35 | QueryPerformanceFrequency(&frequency);
36 | ever = 1;
37 | }
38 | LARGE_INTEGER t;
39 | QueryPerformanceCounter(&t);
40 | return (t.QuadPart * (uint64_t) 1e9) / frequency.QuadPart;
41 | #else // __linux
42 | struct timespec t;
43 | if (!ever) {
44 | if (clock_gettime(CLOCK_MONOTONIC, &t) != 0) {
45 | return 0;
46 | }
47 | ever = 1;
48 | }
49 | clock_gettime(CLOCK_MONOTONIC, &t);
50 | return (t.tv_sec * (uint64_t) 1e9) + t.tv_nsec;
51 | #endif
52 | }
53 |
54 |
55 | static double now() {
56 | static uint64_t epoch = 0;
57 | if (!epoch) {
58 | epoch = nanotimer();
59 | }
60 | return (nanotimer() - epoch) / 1e9;
61 | };
62 |
63 | double calcElapsed(double start, double end) {
64 | double took = -start;
65 | return took + end;
66 | }
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // noiseReduction
4 | //
5 | // Created by LJP on 2018/8/23.
6 | // Copyright © 2018 LJP. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 |
24 | - (void)applicationWillResignActive:(UIApplication *)application {
25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
27 | }
28 |
29 |
30 | - (void)applicationDidEnterBackground:(UIApplication *)application {
31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
33 | }
34 |
35 |
36 | - (void)applicationWillEnterForeground:(UIApplication *)application {
37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
38 | }
39 |
40 |
41 | - (void)applicationDidBecomeActive:(UIApplication *)application {
42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
43 | }
44 |
45 |
46 | - (void)applicationWillTerminate:(UIApplication *)application {
47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
48 | }
49 |
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // noiseReduction
4 | //
5 | // Created by LJP on 2018/8/23.
6 | // Copyright © 2018 LJP. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 |
11 | #define DR_WAV_IMPLEMENTATION
12 |
13 | #include "dr_wav.h"
14 | #include "timing.h"
15 | #include "noise_suppression.h"
16 |
17 | #ifndef nullptr
18 | #define nullptr 0
19 | #endif
20 |
21 | #ifndef MIN
22 | #define MIN(A, B) ((A) < (B) ? (A) : (B))
23 | #endif
24 |
25 | enum nsLevel {
26 | kLow,
27 | kModerate,
28 | kHigh,
29 | kVeryHigh
30 | };
31 |
32 | @interface ViewController ()
33 |
34 | @end
35 |
36 | @implementation ViewController
37 |
38 | - (void)viewDidLoad {
39 |
40 | [super viewDidLoad];
41 |
42 | NSString *inpath = @"/Users/apple/Desktop/a.wav";
43 | NSString *outpath = @"/Users/apple/Desktop/b.wav";
44 |
45 | const char *in_file = [inpath UTF8String];
46 | const char *out_file = [outpath UTF8String];
47 |
48 | char in_f[1024];
49 | //把从src地址开始且含有'\0'结束符的字符串复制到以dest开始的地址空间,返回值的类型为char*
50 | strcpy(in_f,in_file);
51 |
52 | char out_f[1024];
53 | strcpy(out_f,out_file);
54 |
55 | [self noise_suppression:in_f and:out_f];
56 | }
57 |
58 |
59 | - (void)noise_suppression:(char *)in_file and:(char *)out_file {
60 | //音频采样率
61 | uint32_t sampleRate = 0;
62 | //总音频采样数
63 | uint64_t inSampleCount = 0;
64 |
65 | int16_t *inBuffer = [self wavRead_int16:in_file :&sampleRate :&inSampleCount];
66 |
67 | //如果加载成功
68 | if (inBuffer != nullptr) {
69 | double startTime = now();
70 | [self nsProcess:inBuffer :sampleRate :(int)inSampleCount :kModerate];
71 | double time_interval = calcElapsed(startTime, now());
72 | printf("time interval: %d ms\n ", (int) (time_interval * 1000));
73 | [self wavWrite_int16:out_file :inBuffer :sampleRate :inSampleCount];
74 | free(inBuffer);
75 | }
76 | }
77 |
78 | //写wav文件
79 | - (void)wavWrite_int16:(char *)filename :(int16_t *)buffer :(size_t)sampleRate :(size_t)totalSampleCount {
80 | drwav_data_format format = {};
81 | format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
82 | format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes.
83 | format.channels = 1;
84 | format.sampleRate = (drwav_uint32)sampleRate;
85 | format.bitsPerSample = 16;
86 | drwav *pWav = drwav_open_file_write(filename, &format);
87 | if (pWav) {
88 | drwav_uint64 samplesWritten = drwav_write(pWav, totalSampleCount, buffer);
89 | drwav_uninit(pWav);
90 | if (samplesWritten != totalSampleCount) {
91 | fprintf(stderr, "ERROR\n");
92 | exit(1);
93 | }
94 | }
95 | }
96 |
97 | //读取wav文件
98 | - (int16_t *)wavRead_int16:(char *)filename :(uint32_t *)sampleRate :(uint64_t *)totalSampleCount{
99 | unsigned int channels;
100 | int16_t *buffer = drwav_open_and_read_file_s16(filename, &channels, sampleRate, totalSampleCount);
101 | if (buffer == nullptr) {
102 | printf("ERROR.");
103 | }
104 | return buffer;
105 | }
106 |
107 | -(int)nsProcess:(int16_t *)buffer :(uint32_t)sampleRate :(int)samplesCount :(enum nsLevel)level {
108 | if (buffer == nullptr) return -1;
109 | if (samplesCount == 0) return -1;
110 | size_t samples = MIN(160, sampleRate / 100);
111 | if (samples == 0) return -1;
112 | uint32_t num_bands = 1;
113 | int16_t *input = buffer;
114 | size_t nTotal = (samplesCount / samples);
115 | NsHandle *nsHandle = WebRtcNs_Create();
116 | int status = WebRtcNs_Init(nsHandle, sampleRate);
117 | if (status != 0) {
118 | printf("WebRtcNs_Init fail\n");
119 | return -1;
120 | }
121 | status = WebRtcNs_set_policy(nsHandle, level);
122 | if (status != 0) {
123 | printf("WebRtcNs_set_policy fail\n");
124 | return -1;
125 | }
126 | for (int i = 0; i < nTotal; i++) {
127 | int16_t *nsIn[1] = {input}; //ns input[band][data]
128 | int16_t *nsOut[1] = {input}; //ns output[band][data]
129 | WebRtcNs_Analyze(nsHandle, nsIn[0]);
130 | WebRtcNs_Process(nsHandle, (const int16_t *const *) nsIn, num_bands, nsOut);
131 | input += samples;
132 | }
133 | WebRtcNs_Free(nsHandle);
134 |
135 | return 1;
136 | }
137 |
138 |
139 | @end
140 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction/SDK/noise_suppression.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 | *
4 | * Use of this source code is governed by a BSD-style license
5 | * that can be found in the LICENSE file in the root of the source
6 | * tree. An additional intellectual property rights grant can be found
7 | * in the file PATENTS. All contributing project authors may
8 | * be found in the AUTHORS file in the root of the source tree.
9 | */
10 | #ifndef WEBRTC_MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSION_H_
11 | #define WEBRTC_MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSION_H_
12 |
13 | #include
14 | #include
15 |
16 | #define BLOCKL_MAX 160 // max processing block length: 160
17 | #define ANAL_BLOCKL_MAX 256 // max analysis block length: 256
18 | #define HALF_ANAL_BLOCKL 129 // half max analysis block length + 1
19 | #define NUM_HIGH_BANDS_MAX 2 // max number of high bands: 2
20 |
21 | #define QUANTILE (float)0.25
22 |
23 | #define SIMULT 3
24 | #define END_STARTUP_LONG 200
25 | #define END_STARTUP_SHORT 50
26 | #define FACTOR (float)40.0
27 | #define WIDTH (float)0.01
28 |
29 | // Length of fft work arrays.
30 | #define IP_LENGTH (ANAL_BLOCKL_MAX >> 1) // must be at least ceil(2 + sqrt(ANAL_BLOCKL_MAX/2))
31 | #define W_LENGTH (ANAL_BLOCKL_MAX >> 1)
32 |
33 | //PARAMETERS FOR NEW METHOD
34 | #define DD_PR_SNR (float)0.98 // DD update of prior SNR
35 | #define LRT_TAVG (float)0.50 // tavg parameter for LRT (previously 0.90)
36 | #define SPECT_FL_TAVG (float)0.30 // tavg parameter for spectral flatness measure
37 | #define SPECT_DIFF_TAVG (float)0.30 // tavg parameter for spectral difference measure
38 | #define PRIOR_UPDATE (float)0.10 // update parameter of prior model
39 | #define NOISE_UPDATE (float)0.90 // update parameter for noise
40 | #define SPEECH_UPDATE (float)0.99 // update parameter when likely speech
41 | #define WIDTH_PR_MAP (float)4.0 // width parameter in sigmoid map for prior model
42 | #define LRT_FEATURE_THR (float)0.5 // default threshold for LRT feature
43 | #define SF_FEATURE_THR (float)0.5 // default threshold for Spectral Flatness feature
44 | #define PROB_RANGE (float)0.20 // probability threshold for noise state in
45 | // speech/noise likelihood
46 | #define HIST_PAR_EST 1000 // histogram size for estimation of parameters
47 | #define GAMMA_PAUSE (float)0.05 // update for conservative noise estimate
48 | //
49 | #define B_LIM (float)0.5 // threshold in final energy gain factor calculation
50 |
51 |
52 | #include
53 |
54 |
55 | typedef struct NsHandleT NsHandle;
56 |
57 | #ifdef __cplusplus
58 | extern "C" {
59 | #endif
60 |
61 | typedef struct NSParaExtract_ {
62 | // Bin size of histogram.
63 | float binSizeLrt;
64 | float binSizeSpecFlat;
65 | float binSizeSpecDiff;
66 | // Range of histogram over which LRT threshold is computed.
67 | float rangeAvgHistLrt;
68 | // Scale parameters: multiply dominant peaks of the histograms by scale factor
69 | // to obtain thresholds for prior model.
70 | float factor1ModelPars; // For LRT and spectral difference.
71 | float factor2ModelPars; // For spectral_flatness: used when noise is flatter
72 | // than speech.
73 | // Peak limit for spectral flatness (varies between 0 and 1).
74 | float thresPosSpecFlat;
75 | // Limit on spacing of two highest peaks in histogram: spacing determined by
76 | // bin size.
77 | float limitPeakSpacingSpecFlat;
78 | float limitPeakSpacingSpecDiff;
79 | // Limit on relevance of second peak.
80 | float limitPeakWeightsSpecFlat;
81 | float limitPeakWeightsSpecDiff;
82 | // Limit on fluctuation of LRT feature.
83 | float thresFluctLrt;
84 | // Limit on the max and min values for the feature thresholds.
85 | float maxLrt;
86 | float minLrt;
87 | float maxSpecFlat;
88 | float minSpecFlat;
89 | float maxSpecDiff;
90 | float minSpecDiff;
91 | // Criteria of weight of histogram peak to accept/reject feature.
92 | int thresWeightSpecFlat;
93 | int thresWeightSpecDiff;
94 |
95 | } NSParaExtract;
96 |
97 | typedef struct NoiseSuppressionC_ {
98 | uint32_t fs;
99 | size_t blockLen;
100 | size_t windShift;
101 | size_t anaLen;
102 | size_t magnLen;
103 | int aggrMode;
104 | const float *window;
105 | float analyzeBuf[ANAL_BLOCKL_MAX];
106 | float dataBuf[ANAL_BLOCKL_MAX];
107 | float syntBuf[ANAL_BLOCKL_MAX];
108 |
109 | int initFlag;
110 | // Parameters for quantile noise estimation.
111 | float density[SIMULT * HALF_ANAL_BLOCKL];
112 | float lquantile[SIMULT * HALF_ANAL_BLOCKL];
113 | float quantile[HALF_ANAL_BLOCKL];
114 | int counter[SIMULT];
115 | int updates;
116 | // Parameters for Wiener filter.
117 | float smooth[HALF_ANAL_BLOCKL];
118 | float overdrive;
119 | float denoiseBound;
120 | int gainmap;
121 | // FFT work arrays.
122 | size_t ip[IP_LENGTH];
123 | float wfft[W_LENGTH];
124 |
125 | // Parameters for new method: some not needed, will reduce/cleanup later.
126 | int32_t blockInd; // Frame index counter.
127 | int modelUpdatePars[4]; // Parameters for updating or estimating.
128 | // Thresholds/weights for prior model.
129 | float priorModelPars[7]; // Parameters for prior model.
130 | float noise[HALF_ANAL_BLOCKL]; // Noise spectrum from current frame.
131 | float noisePrev[HALF_ANAL_BLOCKL]; // Noise spectrum from previous frame.
132 | // Magnitude spectrum of previous analyze frame.
133 | float magnPrevAnalyze[HALF_ANAL_BLOCKL];
134 | // Magnitude spectrum of previous process frame.
135 | float magnPrevProcess[HALF_ANAL_BLOCKL];
136 | float logLrtTimeAvg[HALF_ANAL_BLOCKL]; // Log LRT factor with time-smoothing.
137 | float priorSpeechProb; // Prior speech/noise probability.
138 | float featureData[7];
139 | // Conservative noise spectrum estimate.
140 | float magnAvgPause[HALF_ANAL_BLOCKL];
141 | float signalEnergy; // Energy of |magn|.
142 | float sumMagn;
143 | float whiteNoiseLevel; // Initial noise estimate.
144 | float initMagnEst[HALF_ANAL_BLOCKL]; // Initial magnitude spectrum estimate.
145 | float pinkNoiseNumerator; // Pink noise parameter: numerator.
146 | float pinkNoiseExp; // Pink noise parameter: power of frequencies.
147 | float parametricNoise[HALF_ANAL_BLOCKL];
148 | // Parameters for feature extraction.
149 | NSParaExtract featureExtractionParams;
150 | // Histograms for parameter estimation.
151 | int histLrt[HIST_PAR_EST];
152 | int histSpecFlat[HIST_PAR_EST];
153 | int histSpecDiff[HIST_PAR_EST];
154 | // Quantities for high band estimate.
155 | float speechProb[HALF_ANAL_BLOCKL]; // Final speech/noise prob: prior + LRT.
156 | // Buffering data for HB.
157 | float dataBufHB[NUM_HIGH_BANDS_MAX][ANAL_BLOCKL_MAX];
158 |
159 | } NoiseSuppressionC;
160 |
161 | // Refer to fft4g.c for documentation.
162 | void WebRtc_rdft(size_t n, int isgn, float *a, size_t *ip, float *w);
163 |
164 | /****************************************************************************
165 | * WebRtcNs_InitCore(...)
166 | *
167 | * This function initializes a noise suppression instance
168 | *
169 | * Input:
170 | * - self : Instance that should be initialized
171 | * - fs : Sampling frequency
172 | *
173 | * Output:
174 | * - self : Initialized instance
175 | *
176 | * Return value : 0 - Ok
177 | * -1 - Error
178 | */
179 | int WebRtcNs_InitCore(NoiseSuppressionC *self, uint32_t fs);
180 |
181 | /****************************************************************************
182 | * WebRtcNs_set_policy_core(...)
183 | *
184 | * This changes the aggressiveness of the noise suppression method.
185 | *
186 | * Input:
187 | * - self : Instance that should be initialized
188 | * - mode : 0: Mild (6dB), 1: Medium (10dB), 2: Aggressive (15dB)
189 | *
190 | * Output:
191 | * - self : Initialized instance
192 | *
193 | * Return value : 0 - Ok
194 | * -1 - Error
195 | */
196 | int WebRtcNs_set_policy_core(NoiseSuppressionC *self, int mode);
197 |
198 | /****************************************************************************
199 | * WebRtcNs_AnalyzeCore
200 | *
201 | * Estimate the background noise.
202 | *
203 | * Input:
204 | * - self : Instance that should be initialized
205 | * - speechFrame : Input speech frame for lower band
206 | *
207 | * Output:
208 | * - self : Updated instance
209 | */
210 | void WebRtcNs_AnalyzeCore(NoiseSuppressionC *self, const int16_t *speechFrame);
211 |
212 | /****************************************************************************
213 | * WebRtcNs_ProcessCore
214 | *
215 | * Do noise suppression.
216 | *
217 | * Input:
218 | * - self : Instance that should be initialized
219 | * - inFrame : Input speech frame for each band
220 | * - num_bands : Number of bands
221 | *
222 | * Output:
223 | * - self : Updated instance
224 | * - outFrame : Output speech frame for each band
225 | */
226 | void WebRtcNs_ProcessCore(NoiseSuppressionC *self,
227 | const int16_t *const *inFrame,
228 | size_t num_bands,
229 | int16_t *const *outFrame);
230 |
231 | /*
232 | * This function creates an instance of the floating point Noise Suppression.
233 | */
234 | NsHandle *WebRtcNs_Create();
235 |
236 | /*
237 | * This function frees the dynamic memory of a specified noise suppression
238 | * instance.
239 | *
240 | * Input:
241 | * - NS_inst : Pointer to NS instance that should be freed
242 | */
243 | void WebRtcNs_Free(NsHandle *NS_inst);
244 |
245 | /*
246 | * This function initializes a NS instance and has to be called before any other
247 | * processing is made.
248 | *
249 | * Input:
250 | * - NS_inst : Instance that should be initialized
251 | * - fs : sampling frequency
252 | *
253 | * Output:
254 | * - NS_inst : Initialized instance
255 | *
256 | * Return value : 0 - Ok
257 | * -1 - Error
258 | */
259 | int WebRtcNs_Init(NsHandle *NS_inst, uint32_t fs);
260 |
261 | /*
262 | * This changes the aggressiveness of the noise suppression method.
263 | *
264 | * Input:
265 | * - NS_inst : Noise suppression instance.
266 | * - mode : 0: Mild, 1: Medium , 2: Aggressive
267 | *
268 | * Output:
269 | * - NS_inst : Updated instance.
270 | *
271 | * Return value : 0 - Ok
272 | * -1 - Error
273 | */
274 | int WebRtcNs_set_policy(NsHandle *NS_inst, int mode);
275 |
276 | /*
277 | * This functions estimates the background noise for the inserted speech frame.
278 | * The input and output signals should always be 10ms (80 or 160 samples).
279 | *
280 | * Input
281 | * - NS_inst : Noise suppression instance.
282 | * - spframe : Pointer to speech frame buffer for L band
283 | *
284 | * Output:
285 | * - NS_inst : Updated NS instance
286 | */
287 | void WebRtcNs_Analyze(NsHandle *NS_inst, const int16_t *spframe);
288 |
289 | /*
290 | * This functions does Noise Suppression for the inserted speech frame. The
291 | * input and output signals should always be 10ms (80 or 160 samples).
292 | *
293 | * Input
294 | * - NS_inst : Noise suppression instance.
295 | * - spframe : Pointer to speech frame buffer for each band
296 | * - num_bands : Number of bands
297 | *
298 | * Output:
299 | * - NS_inst : Updated NS instance
300 | * - outframe : Pointer to output frame for each band
301 | */
302 | void WebRtcNs_Process(NsHandle *NS_inst,
303 | const int16_t *const *spframe,
304 | size_t num_bands,
305 | int16_t *const *outframe);
306 |
307 | /* Returns the internally used prior speech probability of the current frame.
308 | * There is a frequency bin based one as well, with which this should not be
309 | * confused.
310 | *
311 | * Input
312 | * - handle : Noise suppression instance.
313 | *
314 | * Return value : Prior speech probability in interval [0.0, 1.0].
315 | * -1 - NULL pointer or uninitialized instance.
316 | */
317 | float WebRtcNs_prior_speech_probability(NsHandle *handle);
318 |
319 | /* Returns a pointer to the noise estimate per frequency bin. The number of
320 | * frequency bins can be provided using WebRtcNs_num_freq().
321 | *
322 | * Input
323 | * - handle : Noise suppression instance.
324 | *
325 | * Return value : Pointer to the noise estimate per frequency bin.
326 | * Returns NULL if the input is a NULL pointer or an
327 | * uninitialized instance.
328 | */
329 | const float *WebRtcNs_noise_estimate(const NsHandle *handle);
330 |
331 | /* Returns the number of frequency bins, which is the length of the noise
332 | * estimate for example.
333 | *
334 | * Return value : Number of frequency bins.
335 | */
336 | size_t WebRtcNs_num_freq();
337 |
338 | #ifdef __cplusplus
339 | }
340 | #endif
341 |
342 | #endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSION_H_
343 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 48;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 169F0CFA212EAE7000CB72AC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 169F0CF9212EAE7000CB72AC /* AppDelegate.m */; };
11 | 169F0CFD212EAE7000CB72AC /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 169F0CFC212EAE7000CB72AC /* ViewController.m */; };
12 | 169F0D00212EAE7000CB72AC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 169F0CFE212EAE7000CB72AC /* Main.storyboard */; };
13 | 169F0D02212EAE7000CB72AC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 169F0D01212EAE7000CB72AC /* Assets.xcassets */; };
14 | 169F0D05212EAE7000CB72AC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 169F0D03212EAE7000CB72AC /* LaunchScreen.storyboard */; };
15 | 169F0D08212EAE7100CB72AC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 169F0D07212EAE7100CB72AC /* main.m */; };
16 | 169F0D12212EAE7100CB72AC /* noiseReductionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 169F0D11212EAE7100CB72AC /* noiseReductionTests.m */; };
17 | 169F0D1D212EAE7100CB72AC /* noiseReductionUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 169F0D1C212EAE7100CB72AC /* noiseReductionUITests.m */; };
18 | C1E15A39212ED64B00D366FC /* noise_suppression.c in Sources */ = {isa = PBXBuildFile; fileRef = C1E15A36212ED64A00D366FC /* noise_suppression.c */; };
19 | /* End PBXBuildFile section */
20 |
21 | /* Begin PBXContainerItemProxy section */
22 | 169F0D0E212EAE7100CB72AC /* PBXContainerItemProxy */ = {
23 | isa = PBXContainerItemProxy;
24 | containerPortal = 169F0CED212EAE7000CB72AC /* Project object */;
25 | proxyType = 1;
26 | remoteGlobalIDString = 169F0CF4212EAE7000CB72AC;
27 | remoteInfo = noiseReduction;
28 | };
29 | 169F0D19212EAE7100CB72AC /* PBXContainerItemProxy */ = {
30 | isa = PBXContainerItemProxy;
31 | containerPortal = 169F0CED212EAE7000CB72AC /* Project object */;
32 | proxyType = 1;
33 | remoteGlobalIDString = 169F0CF4212EAE7000CB72AC;
34 | remoteInfo = noiseReduction;
35 | };
36 | /* End PBXContainerItemProxy section */
37 |
38 | /* Begin PBXFileReference section */
39 | 169F0CF5212EAE7000CB72AC /* noiseReduction.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = noiseReduction.app; sourceTree = BUILT_PRODUCTS_DIR; };
40 | 169F0CF8212EAE7000CB72AC /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
41 | 169F0CF9212EAE7000CB72AC /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
42 | 169F0CFB212EAE7000CB72AC /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
43 | 169F0CFC212EAE7000CB72AC /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
44 | 169F0CFF212EAE7000CB72AC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
45 | 169F0D01212EAE7000CB72AC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
46 | 169F0D04212EAE7000CB72AC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
47 | 169F0D06212EAE7100CB72AC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
48 | 169F0D07212EAE7100CB72AC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
49 | 169F0D0D212EAE7100CB72AC /* noiseReductionTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = noiseReductionTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
50 | 169F0D11212EAE7100CB72AC /* noiseReductionTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = noiseReductionTests.m; sourceTree = ""; };
51 | 169F0D13212EAE7100CB72AC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
52 | 169F0D18212EAE7100CB72AC /* noiseReductionUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = noiseReductionUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
53 | 169F0D1C212EAE7100CB72AC /* noiseReductionUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = noiseReductionUITests.m; sourceTree = ""; };
54 | 169F0D1E212EAE7100CB72AC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
55 | C1E15A35212ED64A00D366FC /* dr_wav.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dr_wav.h; sourceTree = ""; };
56 | C1E15A36212ED64A00D366FC /* noise_suppression.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = noise_suppression.c; sourceTree = ""; };
57 | C1E15A37212ED64B00D366FC /* noise_suppression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = noise_suppression.h; sourceTree = ""; };
58 | C1E15A38212ED64B00D366FC /* timing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = timing.h; sourceTree = ""; };
59 | /* End PBXFileReference section */
60 |
61 | /* Begin PBXFrameworksBuildPhase section */
62 | 169F0CF2212EAE7000CB72AC /* Frameworks */ = {
63 | isa = PBXFrameworksBuildPhase;
64 | buildActionMask = 2147483647;
65 | files = (
66 | );
67 | runOnlyForDeploymentPostprocessing = 0;
68 | };
69 | 169F0D0A212EAE7100CB72AC /* Frameworks */ = {
70 | isa = PBXFrameworksBuildPhase;
71 | buildActionMask = 2147483647;
72 | files = (
73 | );
74 | runOnlyForDeploymentPostprocessing = 0;
75 | };
76 | 169F0D15212EAE7100CB72AC /* Frameworks */ = {
77 | isa = PBXFrameworksBuildPhase;
78 | buildActionMask = 2147483647;
79 | files = (
80 | );
81 | runOnlyForDeploymentPostprocessing = 0;
82 | };
83 | /* End PBXFrameworksBuildPhase section */
84 |
85 | /* Begin PBXGroup section */
86 | 169F0CEC212EAE7000CB72AC = {
87 | isa = PBXGroup;
88 | children = (
89 | 169F0CF7212EAE7000CB72AC /* noiseReduction */,
90 | 169F0D10212EAE7100CB72AC /* noiseReductionTests */,
91 | 169F0D1B212EAE7100CB72AC /* noiseReductionUITests */,
92 | 169F0CF6212EAE7000CB72AC /* Products */,
93 | );
94 | sourceTree = "";
95 | };
96 | 169F0CF6212EAE7000CB72AC /* Products */ = {
97 | isa = PBXGroup;
98 | children = (
99 | 169F0CF5212EAE7000CB72AC /* noiseReduction.app */,
100 | 169F0D0D212EAE7100CB72AC /* noiseReductionTests.xctest */,
101 | 169F0D18212EAE7100CB72AC /* noiseReductionUITests.xctest */,
102 | );
103 | name = Products;
104 | sourceTree = "";
105 | };
106 | 169F0CF7212EAE7000CB72AC /* noiseReduction */ = {
107 | isa = PBXGroup;
108 | children = (
109 | C1E15A3A212ED65000D366FC /* SDK */,
110 | 169F0CF8212EAE7000CB72AC /* AppDelegate.h */,
111 | 169F0CF9212EAE7000CB72AC /* AppDelegate.m */,
112 | 169F0CFB212EAE7000CB72AC /* ViewController.h */,
113 | 169F0CFC212EAE7000CB72AC /* ViewController.m */,
114 | 169F0CFE212EAE7000CB72AC /* Main.storyboard */,
115 | 169F0D01212EAE7000CB72AC /* Assets.xcassets */,
116 | 169F0D03212EAE7000CB72AC /* LaunchScreen.storyboard */,
117 | 169F0D06212EAE7100CB72AC /* Info.plist */,
118 | 169F0D07212EAE7100CB72AC /* main.m */,
119 | );
120 | path = noiseReduction;
121 | sourceTree = "";
122 | };
123 | 169F0D10212EAE7100CB72AC /* noiseReductionTests */ = {
124 | isa = PBXGroup;
125 | children = (
126 | 169F0D11212EAE7100CB72AC /* noiseReductionTests.m */,
127 | 169F0D13212EAE7100CB72AC /* Info.plist */,
128 | );
129 | path = noiseReductionTests;
130 | sourceTree = "";
131 | };
132 | 169F0D1B212EAE7100CB72AC /* noiseReductionUITests */ = {
133 | isa = PBXGroup;
134 | children = (
135 | 169F0D1C212EAE7100CB72AC /* noiseReductionUITests.m */,
136 | 169F0D1E212EAE7100CB72AC /* Info.plist */,
137 | );
138 | path = noiseReductionUITests;
139 | sourceTree = "";
140 | };
141 | C1E15A3A212ED65000D366FC /* SDK */ = {
142 | isa = PBXGroup;
143 | children = (
144 | C1E15A35212ED64A00D366FC /* dr_wav.h */,
145 | C1E15A38212ED64B00D366FC /* timing.h */,
146 | C1E15A37212ED64B00D366FC /* noise_suppression.h */,
147 | C1E15A36212ED64A00D366FC /* noise_suppression.c */,
148 | );
149 | path = SDK;
150 | sourceTree = "";
151 | };
152 | /* End PBXGroup section */
153 |
154 | /* Begin PBXNativeTarget section */
155 | 169F0CF4212EAE7000CB72AC /* noiseReduction */ = {
156 | isa = PBXNativeTarget;
157 | buildConfigurationList = 169F0D21212EAE7100CB72AC /* Build configuration list for PBXNativeTarget "noiseReduction" */;
158 | buildPhases = (
159 | 169F0CF1212EAE7000CB72AC /* Sources */,
160 | 169F0CF2212EAE7000CB72AC /* Frameworks */,
161 | 169F0CF3212EAE7000CB72AC /* Resources */,
162 | );
163 | buildRules = (
164 | );
165 | dependencies = (
166 | );
167 | name = noiseReduction;
168 | productName = noiseReduction;
169 | productReference = 169F0CF5212EAE7000CB72AC /* noiseReduction.app */;
170 | productType = "com.apple.product-type.application";
171 | };
172 | 169F0D0C212EAE7100CB72AC /* noiseReductionTests */ = {
173 | isa = PBXNativeTarget;
174 | buildConfigurationList = 169F0D24212EAE7100CB72AC /* Build configuration list for PBXNativeTarget "noiseReductionTests" */;
175 | buildPhases = (
176 | 169F0D09212EAE7100CB72AC /* Sources */,
177 | 169F0D0A212EAE7100CB72AC /* Frameworks */,
178 | 169F0D0B212EAE7100CB72AC /* Resources */,
179 | );
180 | buildRules = (
181 | );
182 | dependencies = (
183 | 169F0D0F212EAE7100CB72AC /* PBXTargetDependency */,
184 | );
185 | name = noiseReductionTests;
186 | productName = noiseReductionTests;
187 | productReference = 169F0D0D212EAE7100CB72AC /* noiseReductionTests.xctest */;
188 | productType = "com.apple.product-type.bundle.unit-test";
189 | };
190 | 169F0D17212EAE7100CB72AC /* noiseReductionUITests */ = {
191 | isa = PBXNativeTarget;
192 | buildConfigurationList = 169F0D27212EAE7100CB72AC /* Build configuration list for PBXNativeTarget "noiseReductionUITests" */;
193 | buildPhases = (
194 | 169F0D14212EAE7100CB72AC /* Sources */,
195 | 169F0D15212EAE7100CB72AC /* Frameworks */,
196 | 169F0D16212EAE7100CB72AC /* Resources */,
197 | );
198 | buildRules = (
199 | );
200 | dependencies = (
201 | 169F0D1A212EAE7100CB72AC /* PBXTargetDependency */,
202 | );
203 | name = noiseReductionUITests;
204 | productName = noiseReductionUITests;
205 | productReference = 169F0D18212EAE7100CB72AC /* noiseReductionUITests.xctest */;
206 | productType = "com.apple.product-type.bundle.ui-testing";
207 | };
208 | /* End PBXNativeTarget section */
209 |
210 | /* Begin PBXProject section */
211 | 169F0CED212EAE7000CB72AC /* Project object */ = {
212 | isa = PBXProject;
213 | attributes = {
214 | LastUpgradeCheck = 0920;
215 | ORGANIZATIONNAME = LJP;
216 | TargetAttributes = {
217 | 169F0CF4212EAE7000CB72AC = {
218 | CreatedOnToolsVersion = 9.2;
219 | ProvisioningStyle = Automatic;
220 | };
221 | 169F0D0C212EAE7100CB72AC = {
222 | CreatedOnToolsVersion = 9.2;
223 | ProvisioningStyle = Automatic;
224 | TestTargetID = 169F0CF4212EAE7000CB72AC;
225 | };
226 | 169F0D17212EAE7100CB72AC = {
227 | CreatedOnToolsVersion = 9.2;
228 | ProvisioningStyle = Automatic;
229 | TestTargetID = 169F0CF4212EAE7000CB72AC;
230 | };
231 | };
232 | };
233 | buildConfigurationList = 169F0CF0212EAE7000CB72AC /* Build configuration list for PBXProject "noiseReduction" */;
234 | compatibilityVersion = "Xcode 8.0";
235 | developmentRegion = en;
236 | hasScannedForEncodings = 0;
237 | knownRegions = (
238 | en,
239 | Base,
240 | );
241 | mainGroup = 169F0CEC212EAE7000CB72AC;
242 | productRefGroup = 169F0CF6212EAE7000CB72AC /* Products */;
243 | projectDirPath = "";
244 | projectRoot = "";
245 | targets = (
246 | 169F0CF4212EAE7000CB72AC /* noiseReduction */,
247 | 169F0D0C212EAE7100CB72AC /* noiseReductionTests */,
248 | 169F0D17212EAE7100CB72AC /* noiseReductionUITests */,
249 | );
250 | };
251 | /* End PBXProject section */
252 |
253 | /* Begin PBXResourcesBuildPhase section */
254 | 169F0CF3212EAE7000CB72AC /* Resources */ = {
255 | isa = PBXResourcesBuildPhase;
256 | buildActionMask = 2147483647;
257 | files = (
258 | 169F0D05212EAE7000CB72AC /* LaunchScreen.storyboard in Resources */,
259 | 169F0D02212EAE7000CB72AC /* Assets.xcassets in Resources */,
260 | 169F0D00212EAE7000CB72AC /* Main.storyboard in Resources */,
261 | );
262 | runOnlyForDeploymentPostprocessing = 0;
263 | };
264 | 169F0D0B212EAE7100CB72AC /* Resources */ = {
265 | isa = PBXResourcesBuildPhase;
266 | buildActionMask = 2147483647;
267 | files = (
268 | );
269 | runOnlyForDeploymentPostprocessing = 0;
270 | };
271 | 169F0D16212EAE7100CB72AC /* Resources */ = {
272 | isa = PBXResourcesBuildPhase;
273 | buildActionMask = 2147483647;
274 | files = (
275 | );
276 | runOnlyForDeploymentPostprocessing = 0;
277 | };
278 | /* End PBXResourcesBuildPhase section */
279 |
280 | /* Begin PBXSourcesBuildPhase section */
281 | 169F0CF1212EAE7000CB72AC /* Sources */ = {
282 | isa = PBXSourcesBuildPhase;
283 | buildActionMask = 2147483647;
284 | files = (
285 | C1E15A39212ED64B00D366FC /* noise_suppression.c in Sources */,
286 | 169F0CFD212EAE7000CB72AC /* ViewController.m in Sources */,
287 | 169F0D08212EAE7100CB72AC /* main.m in Sources */,
288 | 169F0CFA212EAE7000CB72AC /* AppDelegate.m in Sources */,
289 | );
290 | runOnlyForDeploymentPostprocessing = 0;
291 | };
292 | 169F0D09212EAE7100CB72AC /* Sources */ = {
293 | isa = PBXSourcesBuildPhase;
294 | buildActionMask = 2147483647;
295 | files = (
296 | 169F0D12212EAE7100CB72AC /* noiseReductionTests.m in Sources */,
297 | );
298 | runOnlyForDeploymentPostprocessing = 0;
299 | };
300 | 169F0D14212EAE7100CB72AC /* Sources */ = {
301 | isa = PBXSourcesBuildPhase;
302 | buildActionMask = 2147483647;
303 | files = (
304 | 169F0D1D212EAE7100CB72AC /* noiseReductionUITests.m in Sources */,
305 | );
306 | runOnlyForDeploymentPostprocessing = 0;
307 | };
308 | /* End PBXSourcesBuildPhase section */
309 |
310 | /* Begin PBXTargetDependency section */
311 | 169F0D0F212EAE7100CB72AC /* PBXTargetDependency */ = {
312 | isa = PBXTargetDependency;
313 | target = 169F0CF4212EAE7000CB72AC /* noiseReduction */;
314 | targetProxy = 169F0D0E212EAE7100CB72AC /* PBXContainerItemProxy */;
315 | };
316 | 169F0D1A212EAE7100CB72AC /* PBXTargetDependency */ = {
317 | isa = PBXTargetDependency;
318 | target = 169F0CF4212EAE7000CB72AC /* noiseReduction */;
319 | targetProxy = 169F0D19212EAE7100CB72AC /* PBXContainerItemProxy */;
320 | };
321 | /* End PBXTargetDependency section */
322 |
323 | /* Begin PBXVariantGroup section */
324 | 169F0CFE212EAE7000CB72AC /* Main.storyboard */ = {
325 | isa = PBXVariantGroup;
326 | children = (
327 | 169F0CFF212EAE7000CB72AC /* Base */,
328 | );
329 | name = Main.storyboard;
330 | sourceTree = "";
331 | };
332 | 169F0D03212EAE7000CB72AC /* LaunchScreen.storyboard */ = {
333 | isa = PBXVariantGroup;
334 | children = (
335 | 169F0D04212EAE7000CB72AC /* Base */,
336 | );
337 | name = LaunchScreen.storyboard;
338 | sourceTree = "";
339 | };
340 | /* End PBXVariantGroup section */
341 |
342 | /* Begin XCBuildConfiguration section */
343 | 169F0D1F212EAE7100CB72AC /* Debug */ = {
344 | isa = XCBuildConfiguration;
345 | buildSettings = {
346 | ALWAYS_SEARCH_USER_PATHS = NO;
347 | CLANG_ANALYZER_NONNULL = YES;
348 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
349 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
350 | CLANG_CXX_LIBRARY = "libc++";
351 | CLANG_ENABLE_MODULES = YES;
352 | CLANG_ENABLE_OBJC_ARC = YES;
353 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
354 | CLANG_WARN_BOOL_CONVERSION = YES;
355 | CLANG_WARN_COMMA = YES;
356 | CLANG_WARN_CONSTANT_CONVERSION = YES;
357 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
358 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
359 | CLANG_WARN_EMPTY_BODY = YES;
360 | CLANG_WARN_ENUM_CONVERSION = YES;
361 | CLANG_WARN_INFINITE_RECURSION = YES;
362 | CLANG_WARN_INT_CONVERSION = YES;
363 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
364 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
365 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
366 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
367 | CLANG_WARN_STRICT_PROTOTYPES = YES;
368 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
369 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
370 | CLANG_WARN_UNREACHABLE_CODE = YES;
371 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
372 | CODE_SIGN_IDENTITY = "iPhone Developer";
373 | COPY_PHASE_STRIP = NO;
374 | DEBUG_INFORMATION_FORMAT = dwarf;
375 | ENABLE_STRICT_OBJC_MSGSEND = YES;
376 | ENABLE_TESTABILITY = YES;
377 | GCC_C_LANGUAGE_STANDARD = gnu11;
378 | GCC_DYNAMIC_NO_PIC = NO;
379 | GCC_NO_COMMON_BLOCKS = YES;
380 | GCC_OPTIMIZATION_LEVEL = 0;
381 | GCC_PREPROCESSOR_DEFINITIONS = (
382 | "DEBUG=1",
383 | "$(inherited)",
384 | );
385 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
386 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
387 | GCC_WARN_UNDECLARED_SELECTOR = YES;
388 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
389 | GCC_WARN_UNUSED_FUNCTION = YES;
390 | GCC_WARN_UNUSED_VARIABLE = YES;
391 | IPHONEOS_DEPLOYMENT_TARGET = 11.2;
392 | MTL_ENABLE_DEBUG_INFO = YES;
393 | ONLY_ACTIVE_ARCH = YES;
394 | SDKROOT = iphoneos;
395 | };
396 | name = Debug;
397 | };
398 | 169F0D20212EAE7100CB72AC /* Release */ = {
399 | isa = XCBuildConfiguration;
400 | buildSettings = {
401 | ALWAYS_SEARCH_USER_PATHS = NO;
402 | CLANG_ANALYZER_NONNULL = YES;
403 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
404 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
405 | CLANG_CXX_LIBRARY = "libc++";
406 | CLANG_ENABLE_MODULES = YES;
407 | CLANG_ENABLE_OBJC_ARC = YES;
408 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
409 | CLANG_WARN_BOOL_CONVERSION = YES;
410 | CLANG_WARN_COMMA = YES;
411 | CLANG_WARN_CONSTANT_CONVERSION = YES;
412 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
413 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
414 | CLANG_WARN_EMPTY_BODY = YES;
415 | CLANG_WARN_ENUM_CONVERSION = YES;
416 | CLANG_WARN_INFINITE_RECURSION = YES;
417 | CLANG_WARN_INT_CONVERSION = YES;
418 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
419 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
420 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
421 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
422 | CLANG_WARN_STRICT_PROTOTYPES = YES;
423 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
424 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
425 | CLANG_WARN_UNREACHABLE_CODE = YES;
426 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
427 | CODE_SIGN_IDENTITY = "iPhone Developer";
428 | COPY_PHASE_STRIP = NO;
429 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
430 | ENABLE_NS_ASSERTIONS = NO;
431 | ENABLE_STRICT_OBJC_MSGSEND = YES;
432 | GCC_C_LANGUAGE_STANDARD = gnu11;
433 | GCC_NO_COMMON_BLOCKS = YES;
434 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
435 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
436 | GCC_WARN_UNDECLARED_SELECTOR = YES;
437 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
438 | GCC_WARN_UNUSED_FUNCTION = YES;
439 | GCC_WARN_UNUSED_VARIABLE = YES;
440 | IPHONEOS_DEPLOYMENT_TARGET = 11.2;
441 | MTL_ENABLE_DEBUG_INFO = NO;
442 | SDKROOT = iphoneos;
443 | VALIDATE_PRODUCT = YES;
444 | };
445 | name = Release;
446 | };
447 | 169F0D22212EAE7100CB72AC /* Debug */ = {
448 | isa = XCBuildConfiguration;
449 | buildSettings = {
450 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
451 | CODE_SIGN_STYLE = Automatic;
452 | DEVELOPMENT_TEAM = G583SJY324;
453 | INFOPLIST_FILE = noiseReduction/Info.plist;
454 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
455 | PRODUCT_BUNDLE_IDENTIFIER = "-------------.noiseReduction";
456 | PRODUCT_NAME = "$(TARGET_NAME)";
457 | TARGETED_DEVICE_FAMILY = "1,2";
458 | };
459 | name = Debug;
460 | };
461 | 169F0D23212EAE7100CB72AC /* Release */ = {
462 | isa = XCBuildConfiguration;
463 | buildSettings = {
464 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
465 | CODE_SIGN_STYLE = Automatic;
466 | DEVELOPMENT_TEAM = G583SJY324;
467 | INFOPLIST_FILE = noiseReduction/Info.plist;
468 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
469 | PRODUCT_BUNDLE_IDENTIFIER = "-------------.noiseReduction";
470 | PRODUCT_NAME = "$(TARGET_NAME)";
471 | TARGETED_DEVICE_FAMILY = "1,2";
472 | };
473 | name = Release;
474 | };
475 | 169F0D25212EAE7100CB72AC /* Debug */ = {
476 | isa = XCBuildConfiguration;
477 | buildSettings = {
478 | BUNDLE_LOADER = "$(TEST_HOST)";
479 | CODE_SIGN_STYLE = Automatic;
480 | INFOPLIST_FILE = noiseReductionTests/Info.plist;
481 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
482 | PRODUCT_BUNDLE_IDENTIFIER = "-------------.noiseReductionTests";
483 | PRODUCT_NAME = "$(TARGET_NAME)";
484 | TARGETED_DEVICE_FAMILY = "1,2";
485 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/noiseReduction.app/noiseReduction";
486 | };
487 | name = Debug;
488 | };
489 | 169F0D26212EAE7100CB72AC /* Release */ = {
490 | isa = XCBuildConfiguration;
491 | buildSettings = {
492 | BUNDLE_LOADER = "$(TEST_HOST)";
493 | CODE_SIGN_STYLE = Automatic;
494 | INFOPLIST_FILE = noiseReductionTests/Info.plist;
495 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
496 | PRODUCT_BUNDLE_IDENTIFIER = "-------------.noiseReductionTests";
497 | PRODUCT_NAME = "$(TARGET_NAME)";
498 | TARGETED_DEVICE_FAMILY = "1,2";
499 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/noiseReduction.app/noiseReduction";
500 | };
501 | name = Release;
502 | };
503 | 169F0D28212EAE7100CB72AC /* Debug */ = {
504 | isa = XCBuildConfiguration;
505 | buildSettings = {
506 | CODE_SIGN_STYLE = Automatic;
507 | INFOPLIST_FILE = noiseReductionUITests/Info.plist;
508 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
509 | PRODUCT_BUNDLE_IDENTIFIER = "-------------.noiseReductionUITests";
510 | PRODUCT_NAME = "$(TARGET_NAME)";
511 | TARGETED_DEVICE_FAMILY = "1,2";
512 | TEST_TARGET_NAME = noiseReduction;
513 | };
514 | name = Debug;
515 | };
516 | 169F0D29212EAE7100CB72AC /* Release */ = {
517 | isa = XCBuildConfiguration;
518 | buildSettings = {
519 | CODE_SIGN_STYLE = Automatic;
520 | INFOPLIST_FILE = noiseReductionUITests/Info.plist;
521 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
522 | PRODUCT_BUNDLE_IDENTIFIER = "-------------.noiseReductionUITests";
523 | PRODUCT_NAME = "$(TARGET_NAME)";
524 | TARGETED_DEVICE_FAMILY = "1,2";
525 | TEST_TARGET_NAME = noiseReduction;
526 | };
527 | name = Release;
528 | };
529 | /* End XCBuildConfiguration section */
530 |
531 | /* Begin XCConfigurationList section */
532 | 169F0CF0212EAE7000CB72AC /* Build configuration list for PBXProject "noiseReduction" */ = {
533 | isa = XCConfigurationList;
534 | buildConfigurations = (
535 | 169F0D1F212EAE7100CB72AC /* Debug */,
536 | 169F0D20212EAE7100CB72AC /* Release */,
537 | );
538 | defaultConfigurationIsVisible = 0;
539 | defaultConfigurationName = Release;
540 | };
541 | 169F0D21212EAE7100CB72AC /* Build configuration list for PBXNativeTarget "noiseReduction" */ = {
542 | isa = XCConfigurationList;
543 | buildConfigurations = (
544 | 169F0D22212EAE7100CB72AC /* Debug */,
545 | 169F0D23212EAE7100CB72AC /* Release */,
546 | );
547 | defaultConfigurationIsVisible = 0;
548 | defaultConfigurationName = Release;
549 | };
550 | 169F0D24212EAE7100CB72AC /* Build configuration list for PBXNativeTarget "noiseReductionTests" */ = {
551 | isa = XCConfigurationList;
552 | buildConfigurations = (
553 | 169F0D25212EAE7100CB72AC /* Debug */,
554 | 169F0D26212EAE7100CB72AC /* Release */,
555 | );
556 | defaultConfigurationIsVisible = 0;
557 | defaultConfigurationName = Release;
558 | };
559 | 169F0D27212EAE7100CB72AC /* Build configuration list for PBXNativeTarget "noiseReductionUITests" */ = {
560 | isa = XCConfigurationList;
561 | buildConfigurations = (
562 | 169F0D28212EAE7100CB72AC /* Debug */,
563 | 169F0D29212EAE7100CB72AC /* Release */,
564 | );
565 | defaultConfigurationIsVisible = 0;
566 | defaultConfigurationName = Release;
567 | };
568 | /* End XCConfigurationList section */
569 | };
570 | rootObject = 169F0CED212EAE7000CB72AC /* Project object */;
571 | }
572 |
--------------------------------------------------------------------------------
/noiseReduction/noiseReduction/SDK/noise_suppression.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 | *
4 | * Use of this source code is governed by a BSD-style license
5 | * that can be found in the LICENSE file in the root of the source
6 | * tree. An additional intellectual property rights grant can be found
7 | * in the file PATENTS. All contributing project authors may
8 | * be found in the AUTHORS file in the root of the source tree.
9 | */
10 |
11 | #include "noise_suppression.h"
12 |
13 | #include
14 | #include
15 | #include
16 |
17 | #ifndef SPL_SAT
18 | #define SPL_SAT(a, b, c) ((b) > (a) ? (a) : (b) < (c) ? (c) : (b))
19 | #endif
20 |
21 | // hybrib Hanning & flat window
22 | static const float kBlocks80w128[128] = {
23 | (float) 0.00000000, (float) 0.03271908, (float) 0.06540313, (float) 0.09801714, (float) 0.13052619,
24 | (float) 0.16289547, (float) 0.19509032, (float) 0.22707626, (float) 0.25881905, (float) 0.29028468,
25 | (float) 0.32143947, (float) 0.35225005, (float) 0.38268343, (float) 0.41270703, (float) 0.44228869,
26 | (float) 0.47139674, (float) 0.50000000, (float) 0.52806785, (float) 0.55557023, (float) 0.58247770,
27 | (float) 0.60876143, (float) 0.63439328, (float) 0.65934582, (float) 0.68359230, (float) 0.70710678,
28 | (float) 0.72986407, (float) 0.75183981, (float) 0.77301045, (float) 0.79335334, (float) 0.81284668,
29 | (float) 0.83146961, (float) 0.84920218, (float) 0.86602540, (float) 0.88192126, (float) 0.89687274,
30 | (float) 0.91086382, (float) 0.92387953, (float) 0.93590593, (float) 0.94693013, (float) 0.95694034,
31 | (float) 0.96592583, (float) 0.97387698, (float) 0.98078528, (float) 0.98664333, (float) 0.99144486,
32 | (float) 0.99518473, (float) 0.99785892, (float) 0.99946459, (float) 1.00000000, (float) 1.00000000,
33 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
34 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
35 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
36 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
37 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
38 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
39 | (float) 1.00000000, (float) 0.99946459, (float) 0.99785892, (float) 0.99518473, (float) 0.99144486,
40 | (float) 0.98664333, (float) 0.98078528, (float) 0.97387698, (float) 0.96592583, (float) 0.95694034,
41 | (float) 0.94693013, (float) 0.93590593, (float) 0.92387953, (float) 0.91086382, (float) 0.89687274,
42 | (float) 0.88192126, (float) 0.86602540, (float) 0.84920218, (float) 0.83146961, (float) 0.81284668,
43 | (float) 0.79335334, (float) 0.77301045, (float) 0.75183981, (float) 0.72986407, (float) 0.70710678,
44 | (float) 0.68359230, (float) 0.65934582, (float) 0.63439328, (float) 0.60876143, (float) 0.58247770,
45 | (float) 0.55557023, (float) 0.52806785, (float) 0.50000000, (float) 0.47139674, (float) 0.44228869,
46 | (float) 0.41270703, (float) 0.38268343, (float) 0.35225005, (float) 0.32143947, (float) 0.29028468,
47 | (float) 0.25881905, (float) 0.22707626, (float) 0.19509032, (float) 0.16289547, (float) 0.13052619,
48 | (float) 0.09801714, (float) 0.06540313, (float) 0.03271908
49 | };
50 |
51 | // hybrib Hanning & flat window
52 | static const float kBlocks160w256[256] = {
53 | (float) 0.00000000, (float) 0.01636173, (float) 0.03271908, (float) 0.04906767, (float) 0.06540313,
54 | (float) 0.08172107, (float) 0.09801714, (float) 0.11428696, (float) 0.13052619, (float) 0.14673047,
55 | (float) 0.16289547, (float) 0.17901686, (float) 0.19509032, (float) 0.21111155, (float) 0.22707626,
56 | (float) 0.24298018, (float) 0.25881905, (float) 0.27458862, (float) 0.29028468, (float) 0.30590302,
57 | (float) 0.32143947, (float) 0.33688985, (float) 0.35225005, (float) 0.36751594, (float) 0.38268343,
58 | (float) 0.39774847, (float) 0.41270703, (float) 0.42755509, (float) 0.44228869, (float) 0.45690388,
59 | (float) 0.47139674, (float) 0.48576339, (float) 0.50000000, (float) 0.51410274, (float) 0.52806785,
60 | (float) 0.54189158, (float) 0.55557023, (float) 0.56910015, (float) 0.58247770, (float) 0.59569930,
61 | (float) 0.60876143, (float) 0.62166057, (float) 0.63439328, (float) 0.64695615, (float) 0.65934582,
62 | (float) 0.67155895, (float) 0.68359230, (float) 0.69544264, (float) 0.70710678, (float) 0.71858162,
63 | (float) 0.72986407, (float) 0.74095113, (float) 0.75183981, (float) 0.76252720, (float) 0.77301045,
64 | (float) 0.78328675, (float) 0.79335334, (float) 0.80320753, (float) 0.81284668, (float) 0.82226822,
65 | (float) 0.83146961, (float) 0.84044840, (float) 0.84920218, (float) 0.85772861, (float) 0.86602540,
66 | (float) 0.87409034, (float) 0.88192126, (float) 0.88951608, (float) 0.89687274, (float) 0.90398929,
67 | (float) 0.91086382, (float) 0.91749450, (float) 0.92387953, (float) 0.93001722, (float) 0.93590593,
68 | (float) 0.94154407, (float) 0.94693013, (float) 0.95206268, (float) 0.95694034, (float) 0.96156180,
69 | (float) 0.96592583, (float) 0.97003125, (float) 0.97387698, (float) 0.97746197, (float) 0.98078528,
70 | (float) 0.98384601, (float) 0.98664333, (float) 0.98917651, (float) 0.99144486, (float) 0.99344778,
71 | (float) 0.99518473, (float) 0.99665524, (float) 0.99785892, (float) 0.99879546, (float) 0.99946459,
72 | (float) 0.99986614, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
73 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
74 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
75 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
76 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
77 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
78 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
79 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
80 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
81 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
82 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
83 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
84 | (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000, (float) 1.00000000,
85 | (float) 1.00000000, (float) 0.99986614, (float) 0.99946459, (float) 0.99879546, (float) 0.99785892,
86 | (float) 0.99665524, (float) 0.99518473, (float) 0.99344778, (float) 0.99144486, (float) 0.98917651,
87 | (float) 0.98664333, (float) 0.98384601, (float) 0.98078528, (float) 0.97746197, (float) 0.97387698,
88 | (float) 0.97003125, (float) 0.96592583, (float) 0.96156180, (float) 0.95694034, (float) 0.95206268,
89 | (float) 0.94693013, (float) 0.94154407, (float) 0.93590593, (float) 0.93001722, (float) 0.92387953,
90 | (float) 0.91749450, (float) 0.91086382, (float) 0.90398929, (float) 0.89687274, (float) 0.88951608,
91 | (float) 0.88192126, (float) 0.87409034, (float) 0.86602540, (float) 0.85772861, (float) 0.84920218,
92 | (float) 0.84044840, (float) 0.83146961, (float) 0.82226822, (float) 0.81284668, (float) 0.80320753,
93 | (float) 0.79335334, (float) 0.78328675, (float) 0.77301045, (float) 0.76252720, (float) 0.75183981,
94 | (float) 0.74095113, (float) 0.72986407, (float) 0.71858162, (float) 0.70710678, (float) 0.69544264,
95 | (float) 0.68359230, (float) 0.67155895, (float) 0.65934582, (float) 0.64695615, (float) 0.63439328,
96 | (float) 0.62166057, (float) 0.60876143, (float) 0.59569930, (float) 0.58247770, (float) 0.56910015,
97 | (float) 0.55557023, (float) 0.54189158, (float) 0.52806785, (float) 0.51410274, (float) 0.50000000,
98 | (float) 0.48576339, (float) 0.47139674, (float) 0.45690388, (float) 0.44228869, (float) 0.42755509,
99 | (float) 0.41270703, (float) 0.39774847, (float) 0.38268343, (float) 0.36751594, (float) 0.35225005,
100 | (float) 0.33688985, (float) 0.32143947, (float) 0.30590302, (float) 0.29028468, (float) 0.27458862,
101 | (float) 0.25881905, (float) 0.24298018, (float) 0.22707626, (float) 0.21111155, (float) 0.19509032,
102 | (float) 0.17901686, (float) 0.16289547, (float) 0.14673047, (float) 0.13052619, (float) 0.11428696,
103 | (float) 0.09801714, (float) 0.08172107, (float) 0.06540313, (float) 0.04906767, (float) 0.03271908,
104 | (float) 0.01636173
105 | };
106 |
107 | /*
108 | * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html
109 | * Copyright Takuya OOURA, 1996-2001
110 | *
111 | * You may use, copy, modify and distribute this code for any purpose (include
112 | * commercial use) and without fee. Please refer to this package when you modify
113 | * this code.
114 | *
115 | * Changes:
116 | * Trivial type modifications by the WebRTC authors.
117 | */
118 |
119 | static void makewt(size_t nw, size_t *ip, float *w);
120 |
121 | static void makect(size_t nc, size_t *ip, float *c);
122 |
123 | static void bitrv2(size_t n, size_t *ip, float *a);
124 |
125 | static void cftfsub(size_t n, float *a, float *w);
126 |
127 | static void cftbsub(size_t n, float *a, float *w);
128 |
129 | static void cft1st(size_t n, float *a, float *w);
130 |
131 | static void cftmdl(size_t n, size_t l, float *a, float *w);
132 |
133 | static void rftfsub(size_t n, float *a, size_t nc, float *c);
134 |
135 | static void rftbsub(size_t n, float *a, size_t nc, float *c);
136 |
137 |
138 | void WebRtc_rdft(size_t n, int isgn, float *a, size_t *ip, float *w) {
139 | size_t nw, nc;
140 | float xi;
141 |
142 | nw = ip[0];
143 | if (n > (nw << 2)) {
144 | nw = n >> 2;
145 | makewt(nw, ip, w);
146 | }
147 | nc = ip[1];
148 | if (n > (nc << 2)) {
149 | nc = n >> 2;
150 | makect(nc, ip, w + nw);
151 | }
152 | if (isgn >= 0) {
153 | if (n > 4) {
154 | bitrv2(n, ip + 2, a);
155 | cftfsub(n, a, w);
156 | rftfsub(n, a, nc, w + nw);
157 | } else if (n == 4) {
158 | cftfsub(n, a, w);
159 | }
160 | xi = a[0] - a[1];
161 | a[0] += a[1];
162 | a[1] = xi;
163 | } else {
164 | a[1] = 0.5f * (a[0] - a[1]);
165 | a[0] -= a[1];
166 | if (n > 4) {
167 | rftbsub(n, a, nc, w + nw);
168 | bitrv2(n, ip + 2, a);
169 | cftbsub(n, a, w);
170 | } else if (n == 4) {
171 | cftfsub(n, a, w);
172 | }
173 | }
174 | }
175 |
176 | /* -------- initializing routines -------- */
177 |
178 |
179 |
180 | static void makewt(size_t nw, size_t *ip, float *w) {
181 | size_t j, nwh;
182 | float delta, x, y;
183 |
184 | ip[0] = nw;
185 | ip[1] = 1;
186 | if (nw > 2) {
187 | nwh = nw >> 1;
188 | delta = atanf(1.0f) / nwh;
189 | w[0] = 1;
190 | w[1] = 0;
191 | w[nwh] = cosf(delta * nwh);
192 | w[nwh + 1] = w[nwh];
193 | if (nwh > 2) {
194 | for (j = 2; j < nwh; j += 2) {
195 | x = cosf(delta * j);
196 | y = sinf(delta * j);
197 | w[j] = x;
198 | w[j + 1] = y;
199 | w[nw - j] = y;
200 | w[nw - j + 1] = x;
201 | }
202 | bitrv2(nw, ip + 2, w);
203 | }
204 | }
205 | }
206 |
207 |
208 | static void makect(size_t nc, size_t *ip, float *c) {
209 | size_t j, nch;
210 | float delta;
211 |
212 | ip[1] = nc;
213 | if (nc > 1) {
214 | nch = nc >> 1;
215 | delta = atanf(1.0f) / nch;
216 | c[0] = cosf(delta * nch);
217 | c[nch] = 0.5f * c[0];
218 | for (j = 1; j < nch; j++) {
219 | c[j] = 0.5f * cosf(delta * j);
220 | c[nc - j] = 0.5f * sinf(delta * j);
221 | }
222 | }
223 | }
224 |
225 |
226 | /* -------- child routines -------- */
227 |
228 |
229 | static void bitrv2(size_t n, size_t *ip, float *a) {
230 | size_t j, j1, k, k1, l, m, m2;
231 | float xr, xi, yr, yi;
232 |
233 | ip[0] = 0;
234 | l = n;
235 | m = 1;
236 | while ((m << 3) < l) {
237 | l >>= 1;
238 | for (j = 0; j < m; j++) {
239 | ip[m + j] = ip[j] + l;
240 | }
241 | m <<= 1;
242 | }
243 | m2 = 2 * m;
244 | if ((m << 3) == l) {
245 | for (k = 0; k < m; k++) {
246 | for (j = 0; j < k; j++) {
247 | j1 = 2 * j + ip[k];
248 | k1 = 2 * k + ip[j];
249 | xr = a[j1];
250 | xi = a[j1 + 1];
251 | yr = a[k1];
252 | yi = a[k1 + 1];
253 | a[j1] = yr;
254 | a[j1 + 1] = yi;
255 | a[k1] = xr;
256 | a[k1 + 1] = xi;
257 | j1 += m2;
258 | k1 += 2 * m2;
259 | xr = a[j1];
260 | xi = a[j1 + 1];
261 | yr = a[k1];
262 | yi = a[k1 + 1];
263 | a[j1] = yr;
264 | a[j1 + 1] = yi;
265 | a[k1] = xr;
266 | a[k1 + 1] = xi;
267 | j1 += m2;
268 | k1 -= m2;
269 | xr = a[j1];
270 | xi = a[j1 + 1];
271 | yr = a[k1];
272 | yi = a[k1 + 1];
273 | a[j1] = yr;
274 | a[j1 + 1] = yi;
275 | a[k1] = xr;
276 | a[k1 + 1] = xi;
277 | j1 += m2;
278 | k1 += 2 * m2;
279 | xr = a[j1];
280 | xi = a[j1 + 1];
281 | yr = a[k1];
282 | yi = a[k1 + 1];
283 | a[j1] = yr;
284 | a[j1 + 1] = yi;
285 | a[k1] = xr;
286 | a[k1 + 1] = xi;
287 | }
288 | j1 = 2 * k + m2 + ip[k];
289 | k1 = j1 + m2;
290 | xr = a[j1];
291 | xi = a[j1 + 1];
292 | yr = a[k1];
293 | yi = a[k1 + 1];
294 | a[j1] = yr;
295 | a[j1 + 1] = yi;
296 | a[k1] = xr;
297 | a[k1 + 1] = xi;
298 | }
299 | } else {
300 | for (k = 1; k < m; k++) {
301 | for (j = 0; j < k; j++) {
302 | j1 = 2 * j + ip[k];
303 | k1 = 2 * k + ip[j];
304 | xr = a[j1];
305 | xi = a[j1 + 1];
306 | yr = a[k1];
307 | yi = a[k1 + 1];
308 | a[j1] = yr;
309 | a[j1 + 1] = yi;
310 | a[k1] = xr;
311 | a[k1 + 1] = xi;
312 | j1 += m2;
313 | k1 += m2;
314 | xr = a[j1];
315 | xi = a[j1 + 1];
316 | yr = a[k1];
317 | yi = a[k1 + 1];
318 | a[j1] = yr;
319 | a[j1 + 1] = yi;
320 | a[k1] = xr;
321 | a[k1 + 1] = xi;
322 | }
323 | }
324 | }
325 | }
326 |
327 | static void cftfsub(size_t n, float *a, float *w) {
328 | size_t j, j1, j2, j3, l;
329 | float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
330 |
331 | l = 2;
332 | if (n > 8) {
333 | cft1st(n, a, w);
334 | l = 8;
335 | while ((l << 2) < n) {
336 | cftmdl(n, l, a, w);
337 | l <<= 2;
338 | }
339 | }
340 | if ((l << 2) == n) {
341 | for (j = 0; j < l; j += 2) {
342 | j1 = j + l;
343 | j2 = j1 + l;
344 | j3 = j2 + l;
345 | x0r = a[j] + a[j1];
346 | x0i = a[j + 1] + a[j1 + 1];
347 | x1r = a[j] - a[j1];
348 | x1i = a[j + 1] - a[j1 + 1];
349 | x2r = a[j2] + a[j3];
350 | x2i = a[j2 + 1] + a[j3 + 1];
351 | x3r = a[j2] - a[j3];
352 | x3i = a[j2 + 1] - a[j3 + 1];
353 | a[j] = x0r + x2r;
354 | a[j + 1] = x0i + x2i;
355 | a[j2] = x0r - x2r;
356 | a[j2 + 1] = x0i - x2i;
357 | a[j1] = x1r - x3i;
358 | a[j1 + 1] = x1i + x3r;
359 | a[j3] = x1r + x3i;
360 | a[j3 + 1] = x1i - x3r;
361 | }
362 | } else {
363 | for (j = 0; j < l; j += 2) {
364 | j1 = j + l;
365 | x0r = a[j] - a[j1];
366 | x0i = a[j + 1] - a[j1 + 1];
367 | a[j] += a[j1];
368 | a[j + 1] += a[j1 + 1];
369 | a[j1] = x0r;
370 | a[j1 + 1] = x0i;
371 | }
372 | }
373 | }
374 |
375 |
376 | static void cftbsub(size_t n, float *a, float *w) {
377 | size_t j, j1, j2, j3, l;
378 | float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
379 |
380 | l = 2;
381 | if (n > 8) {
382 | cft1st(n, a, w);
383 | l = 8;
384 | while ((l << 2) < n) {
385 | cftmdl(n, l, a, w);
386 | l <<= 2;
387 | }
388 | }
389 | if ((l << 2) == n) {
390 | for (j = 0; j < l; j += 2) {
391 | j1 = j + l;
392 | j2 = j1 + l;
393 | j3 = j2 + l;
394 | x0r = a[j] + a[j1];
395 | x0i = -a[j + 1] - a[j1 + 1];
396 | x1r = a[j] - a[j1];
397 | x1i = -a[j + 1] + a[j1 + 1];
398 | x2r = a[j2] + a[j3];
399 | x2i = a[j2 + 1] + a[j3 + 1];
400 | x3r = a[j2] - a[j3];
401 | x3i = a[j2 + 1] - a[j3 + 1];
402 | a[j] = x0r + x2r;
403 | a[j + 1] = x0i - x2i;
404 | a[j2] = x0r - x2r;
405 | a[j2 + 1] = x0i + x2i;
406 | a[j1] = x1r - x3i;
407 | a[j1 + 1] = x1i - x3r;
408 | a[j3] = x1r + x3i;
409 | a[j3 + 1] = x1i + x3r;
410 | }
411 | } else {
412 | for (j = 0; j < l; j += 2) {
413 | j1 = j + l;
414 | x0r = a[j] - a[j1];
415 | x0i = -a[j + 1] + a[j1 + 1];
416 | a[j] += a[j1];
417 | a[j + 1] = -a[j + 1] - a[j1 + 1];
418 | a[j1] = x0r;
419 | a[j1 + 1] = x0i;
420 | }
421 | }
422 | }
423 |
424 |
425 | static void cft1st(size_t n, float *a, float *w) {
426 | size_t j, k1, k2;
427 | float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i;
428 | float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
429 |
430 | x0r = a[0] + a[2];
431 | x0i = a[1] + a[3];
432 | x1r = a[0] - a[2];
433 | x1i = a[1] - a[3];
434 | x2r = a[4] + a[6];
435 | x2i = a[5] + a[7];
436 | x3r = a[4] - a[6];
437 | x3i = a[5] - a[7];
438 | a[0] = x0r + x2r;
439 | a[1] = x0i + x2i;
440 | a[4] = x0r - x2r;
441 | a[5] = x0i - x2i;
442 | a[2] = x1r - x3i;
443 | a[3] = x1i + x3r;
444 | a[6] = x1r + x3i;
445 | a[7] = x1i - x3r;
446 | wk1r = w[2];
447 | x0r = a[8] + a[10];
448 | x0i = a[9] + a[11];
449 | x1r = a[8] - a[10];
450 | x1i = a[9] - a[11];
451 | x2r = a[12] + a[14];
452 | x2i = a[13] + a[15];
453 | x3r = a[12] - a[14];
454 | x3i = a[13] - a[15];
455 | a[8] = x0r + x2r;
456 | a[9] = x0i + x2i;
457 | a[12] = x2i - x0i;
458 | a[13] = x0r - x2r;
459 | x0r = x1r - x3i;
460 | x0i = x1i + x3r;
461 | a[10] = wk1r * (x0r - x0i);
462 | a[11] = wk1r * (x0r + x0i);
463 | x0r = x3i + x1r;
464 | x0i = x3r - x1i;
465 | a[14] = wk1r * (x0i - x0r);
466 | a[15] = wk1r * (x0i + x0r);
467 | k1 = 0;
468 | for (j = 16; j < n; j += 16) {
469 | k1 += 2;
470 | k2 = 2 * k1;
471 | wk2r = w[k1];
472 | wk2i = w[k1 + 1];
473 | wk1r = w[k2];
474 | wk1i = w[k2 + 1];
475 | wk3r = wk1r - 2 * wk2i * wk1i;
476 | wk3i = 2 * wk2i * wk1r - wk1i;
477 | x0r = a[j] + a[j + 2];
478 | x0i = a[j + 1] + a[j + 3];
479 | x1r = a[j] - a[j + 2];
480 | x1i = a[j + 1] - a[j + 3];
481 | x2r = a[j + 4] + a[j + 6];
482 | x2i = a[j + 5] + a[j + 7];
483 | x3r = a[j + 4] - a[j + 6];
484 | x3i = a[j + 5] - a[j + 7];
485 | a[j] = x0r + x2r;
486 | a[j + 1] = x0i + x2i;
487 | x0r -= x2r;
488 | x0i -= x2i;
489 | a[j + 4] = wk2r * x0r - wk2i * x0i;
490 | a[j + 5] = wk2r * x0i + wk2i * x0r;
491 | x0r = x1r - x3i;
492 | x0i = x1i + x3r;
493 | a[j + 2] = wk1r * x0r - wk1i * x0i;
494 | a[j + 3] = wk1r * x0i + wk1i * x0r;
495 | x0r = x1r + x3i;
496 | x0i = x1i - x3r;
497 | a[j + 6] = wk3r * x0r - wk3i * x0i;
498 | a[j + 7] = wk3r * x0i + wk3i * x0r;
499 | wk1r = w[k2 + 2];
500 | wk1i = w[k2 + 3];
501 | wk3r = wk1r - 2 * wk2r * wk1i;
502 | wk3i = 2 * wk2r * wk1r - wk1i;
503 | x0r = a[j + 8] + a[j + 10];
504 | x0i = a[j + 9] + a[j + 11];
505 | x1r = a[j + 8] - a[j + 10];
506 | x1i = a[j + 9] - a[j + 11];
507 | x2r = a[j + 12] + a[j + 14];
508 | x2i = a[j + 13] + a[j + 15];
509 | x3r = a[j + 12] - a[j + 14];
510 | x3i = a[j + 13] - a[j + 15];
511 | a[j + 8] = x0r + x2r;
512 | a[j + 9] = x0i + x2i;
513 | x0r -= x2r;
514 | x0i -= x2i;
515 | a[j + 12] = -wk2i * x0r - wk2r * x0i;
516 | a[j + 13] = -wk2i * x0i + wk2r * x0r;
517 | x0r = x1r - x3i;
518 | x0i = x1i + x3r;
519 | a[j + 10] = wk1r * x0r - wk1i * x0i;
520 | a[j + 11] = wk1r * x0i + wk1i * x0r;
521 | x0r = x1r + x3i;
522 | x0i = x1i - x3r;
523 | a[j + 14] = wk3r * x0r - wk3i * x0i;
524 | a[j + 15] = wk3r * x0i + wk3i * x0r;
525 | }
526 | }
527 |
528 |
529 | static void cftmdl(size_t n, size_t l, float *a, float *w) {
530 | size_t j, j1, j2, j3, k, k1, k2, m, m2;
531 | float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i;
532 | float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
533 |
534 | m = l << 2;
535 | for (j = 0; j < l; j += 2) {
536 | j1 = j + l;
537 | j2 = j1 + l;
538 | j3 = j2 + l;
539 | x0r = a[j] + a[j1];
540 | x0i = a[j + 1] + a[j1 + 1];
541 | x1r = a[j] - a[j1];
542 | x1i = a[j + 1] - a[j1 + 1];
543 | x2r = a[j2] + a[j3];
544 | x2i = a[j2 + 1] + a[j3 + 1];
545 | x3r = a[j2] - a[j3];
546 | x3i = a[j2 + 1] - a[j3 + 1];
547 | a[j] = x0r + x2r;
548 | a[j + 1] = x0i + x2i;
549 | a[j2] = x0r - x2r;
550 | a[j2 + 1] = x0i - x2i;
551 | a[j1] = x1r - x3i;
552 | a[j1 + 1] = x1i + x3r;
553 | a[j3] = x1r + x3i;
554 | a[j3 + 1] = x1i - x3r;
555 | }
556 | wk1r = w[2];
557 | for (j = m; j < l + m; j += 2) {
558 | j1 = j + l;
559 | j2 = j1 + l;
560 | j3 = j2 + l;
561 | x0r = a[j] + a[j1];
562 | x0i = a[j + 1] + a[j1 + 1];
563 | x1r = a[j] - a[j1];
564 | x1i = a[j + 1] - a[j1 + 1];
565 | x2r = a[j2] + a[j3];
566 | x2i = a[j2 + 1] + a[j3 + 1];
567 | x3r = a[j2] - a[j3];
568 | x3i = a[j2 + 1] - a[j3 + 1];
569 | a[j] = x0r + x2r;
570 | a[j + 1] = x0i + x2i;
571 | a[j2] = x2i - x0i;
572 | a[j2 + 1] = x0r - x2r;
573 | x0r = x1r - x3i;
574 | x0i = x1i + x3r;
575 | a[j1] = wk1r * (x0r - x0i);
576 | a[j1 + 1] = wk1r * (x0r + x0i);
577 | x0r = x3i + x1r;
578 | x0i = x3r - x1i;
579 | a[j3] = wk1r * (x0i - x0r);
580 | a[j3 + 1] = wk1r * (x0i + x0r);
581 | }
582 | k1 = 0;
583 | m2 = 2 * m;
584 | for (k = m2; k < n; k += m2) {
585 | k1 += 2;
586 | k2 = 2 * k1;
587 | wk2r = w[k1];
588 | wk2i = w[k1 + 1];
589 | wk1r = w[k2];
590 | wk1i = w[k2 + 1];
591 | wk3r = wk1r - 2 * wk2i * wk1i;
592 | wk3i = 2 * wk2i * wk1r - wk1i;
593 | for (j = k; j < l + k; j += 2) {
594 | j1 = j + l;
595 | j2 = j1 + l;
596 | j3 = j2 + l;
597 | x0r = a[j] + a[j1];
598 | x0i = a[j + 1] + a[j1 + 1];
599 | x1r = a[j] - a[j1];
600 | x1i = a[j + 1] - a[j1 + 1];
601 | x2r = a[j2] + a[j3];
602 | x2i = a[j2 + 1] + a[j3 + 1];
603 | x3r = a[j2] - a[j3];
604 | x3i = a[j2 + 1] - a[j3 + 1];
605 | a[j] = x0r + x2r;
606 | a[j + 1] = x0i + x2i;
607 | x0r -= x2r;
608 | x0i -= x2i;
609 | a[j2] = wk2r * x0r - wk2i * x0i;
610 | a[j2 + 1] = wk2r * x0i + wk2i * x0r;
611 | x0r = x1r - x3i;
612 | x0i = x1i + x3r;
613 | a[j1] = wk1r * x0r - wk1i * x0i;
614 | a[j1 + 1] = wk1r * x0i + wk1i * x0r;
615 | x0r = x1r + x3i;
616 | x0i = x1i - x3r;
617 | a[j3] = wk3r * x0r - wk3i * x0i;
618 | a[j3 + 1] = wk3r * x0i + wk3i * x0r;
619 | }
620 | wk1r = w[k2 + 2];
621 | wk1i = w[k2 + 3];
622 | wk3r = wk1r - 2 * wk2r * wk1i;
623 | wk3i = 2 * wk2r * wk1r - wk1i;
624 | for (j = k + m; j < l + (k + m); j += 2) {
625 | j1 = j + l;
626 | j2 = j1 + l;
627 | j3 = j2 + l;
628 | x0r = a[j] + a[j1];
629 | x0i = a[j + 1] + a[j1 + 1];
630 | x1r = a[j] - a[j1];
631 | x1i = a[j + 1] - a[j1 + 1];
632 | x2r = a[j2] + a[j3];
633 | x2i = a[j2 + 1] + a[j3 + 1];
634 | x3r = a[j2] - a[j3];
635 | x3i = a[j2 + 1] - a[j3 + 1];
636 | a[j] = x0r + x2r;
637 | a[j + 1] = x0i + x2i;
638 | x0r -= x2r;
639 | x0i -= x2i;
640 | a[j2] = -wk2i * x0r - wk2r * x0i;
641 | a[j2 + 1] = -wk2i * x0i + wk2r * x0r;
642 | x0r = x1r - x3i;
643 | x0i = x1i + x3r;
644 | a[j1] = wk1r * x0r - wk1i * x0i;
645 | a[j1 + 1] = wk1r * x0i + wk1i * x0r;
646 | x0r = x1r + x3i;
647 | x0i = x1i - x3r;
648 | a[j3] = wk3r * x0r - wk3i * x0i;
649 | a[j3 + 1] = wk3r * x0i + wk3i * x0r;
650 | }
651 | }
652 | }
653 |
654 |
655 | static void rftfsub(size_t n, float *a, size_t nc, float *c) {
656 | size_t j, k, kk, ks, m;
657 | float wkr, wki, xr, xi, yr, yi;
658 |
659 | m = n >> 1;
660 | ks = 2 * nc / m;
661 | kk = 0;
662 | for (j = 2; j < m; j += 2) {
663 | k = n - j;
664 | kk += ks;
665 | wkr = 0.5f - c[nc - kk];
666 | wki = c[kk];
667 | xr = a[j] - a[k];
668 | xi = a[j + 1] + a[k + 1];
669 | yr = wkr * xr - wki * xi;
670 | yi = wkr * xi + wki * xr;
671 | a[j] -= yr;
672 | a[j + 1] -= yi;
673 | a[k] += yr;
674 | a[k + 1] -= yi;
675 | }
676 | }
677 |
678 |
679 | static void rftbsub(size_t n, float *a, size_t nc, float *c) {
680 | size_t j, k, kk, ks, m;
681 | float wkr, wki, xr, xi, yr, yi;
682 |
683 | a[1] = -a[1];
684 | m = n >> 1;
685 | ks = 2 * nc / m;
686 | kk = 0;
687 | for (j = 2; j < m; j += 2) {
688 | k = n - j;
689 | kk += ks;
690 | wkr = 0.5f - c[nc - kk];
691 | wki = c[kk];
692 | xr = a[j] - a[k];
693 | xi = a[j + 1] + a[k + 1];
694 | yr = wkr * xr + wki * xi;
695 | yi = wkr * xi - wki * xr;
696 | a[j] -= yr;
697 | a[j + 1] = yi - a[j + 1];
698 | a[k] += yr;
699 | a[k + 1] = yi - a[k + 1];
700 | }
701 | a[m + 1] = -a[m + 1];
702 | }
703 |
704 |
705 | // Set Feature Extraction Parameters.
706 | static void set_feature_extraction_parameters(NoiseSuppressionC *self) {
707 | // Bin size of histogram.
708 | self->featureExtractionParams.binSizeLrt = 0.1f;
709 | self->featureExtractionParams.binSizeSpecFlat = 0.05f;
710 | self->featureExtractionParams.binSizeSpecDiff = 0.1f;
711 |
712 | // Range of histogram over which LRT threshold is computed.
713 | self->featureExtractionParams.rangeAvgHistLrt = 1.f;
714 |
715 | // Scale parameters: multiply dominant peaks of the histograms by scale factor
716 | // to obtain thresholds for prior model.
717 | // For LRT and spectral difference.
718 | self->featureExtractionParams.factor1ModelPars = 1.2f;
719 | // For spectral_flatness: used when noise is flatter than speech.
720 | self->featureExtractionParams.factor2ModelPars = 0.9f;
721 |
722 | // Peak limit for spectral flatness (varies between 0 and 1).
723 | self->featureExtractionParams.thresPosSpecFlat = 0.6f;
724 |
725 | // Limit on spacing of two highest peaks in histogram: spacing determined by
726 | // bin size.
727 | self->featureExtractionParams.limitPeakSpacingSpecFlat =
728 | 2 * self->featureExtractionParams.binSizeSpecFlat;
729 | self->featureExtractionParams.limitPeakSpacingSpecDiff =
730 | 2 * self->featureExtractionParams.binSizeSpecDiff;
731 |
732 | // Limit on relevance of second peak.
733 | self->featureExtractionParams.limitPeakWeightsSpecFlat = 0.5f;
734 | self->featureExtractionParams.limitPeakWeightsSpecDiff = 0.5f;
735 |
736 | // Fluctuation limit of LRT feature.
737 | self->featureExtractionParams.thresFluctLrt = 0.05f;
738 |
739 | // Limit on the max and min values for the feature thresholds.
740 | self->featureExtractionParams.maxLrt = 1.f;
741 | self->featureExtractionParams.minLrt = 0.2f;
742 |
743 | self->featureExtractionParams.maxSpecFlat = 0.95f;
744 | self->featureExtractionParams.minSpecFlat = 0.1f;
745 |
746 | self->featureExtractionParams.maxSpecDiff = 1.f;
747 | self->featureExtractionParams.minSpecDiff = 0.16f;
748 |
749 | // Criteria of weight of histogram peak to accept/reject feature.
750 | self->featureExtractionParams.thresWeightSpecFlat =
751 | (int) (0.3 * (self->modelUpdatePars[1])); // For spectral flatness.
752 | self->featureExtractionParams.thresWeightSpecDiff =
753 | (int) (0.3 * (self->modelUpdatePars[1])); // For spectral difference.
754 | }
755 |
756 | // Initialize state.
757 | int WebRtcNs_InitCore(NoiseSuppressionC *self, uint32_t fs) {
758 | int i;
759 | // Check for valid pointer.
760 | if (self == NULL) {
761 | return -1;
762 | }
763 |
764 | // Initialization of struct.
765 | if (fs == 8000 || fs == 16000 || fs == 32000 || fs == 48000 || fs == 44100) {
766 | self->fs = fs;
767 | } else {
768 | return -1;
769 | }
770 | self->windShift = 0;
771 | // We only support 10ms frames.
772 | if (fs == 8000) {
773 | self->blockLen = 80;
774 | self->anaLen = 128;
775 | self->window = kBlocks80w128;
776 | } else {
777 | self->blockLen = 160;
778 | self->anaLen = 256;
779 | self->window = kBlocks160w256;
780 | }
781 | self->magnLen = self->anaLen / 2 + 1; // Number of frequency bins.
782 |
783 | // Initialize FFT work arrays.
784 | self->ip[0] = 0; // Setting this triggers initialization.
785 | memset(self->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
786 | WebRtc_rdft(self->anaLen, 1, self->dataBuf, self->ip, self->wfft);
787 |
788 | memset(self->analyzeBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
789 | memset(self->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
790 | memset(self->syntBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
791 |
792 | // For HB processing.
793 | memset(self->dataBufHB,
794 | 0,
795 | sizeof(float) * NUM_HIGH_BANDS_MAX * ANAL_BLOCKL_MAX);
796 |
797 | // For quantile noise estimation.
798 | memset(self->quantile, 0, sizeof(float) * HALF_ANAL_BLOCKL);
799 | for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++) {
800 | self->lquantile[i] = 8.f;
801 | self->density[i] = 0.3f;
802 | }
803 |
804 | for (i = 0; i < SIMULT; i++) {
805 | self->counter[i] =
806 | (int) floorf((float) (END_STARTUP_LONG * (i + 1)) / (float) SIMULT);
807 | }
808 |
809 | self->updates = 0;
810 |
811 | // Wiener filter initialization.
812 | for (i = 0; i < HALF_ANAL_BLOCKL; i++) {
813 | self->smooth[i] = 1.f;
814 | }
815 |
816 | // Set the aggressiveness: default.
817 | self->aggrMode = 0;
818 |
819 | // Initialize variables for new method.
820 | self->priorSpeechProb = 0.5f; // Prior prob for speech/noise.
821 | // Previous analyze mag spectrum.
822 | memset(self->magnPrevAnalyze, 0, sizeof(float) * HALF_ANAL_BLOCKL);
823 | // Previous process mag spectrum.
824 | memset(self->magnPrevProcess, 0, sizeof(float) * HALF_ANAL_BLOCKL);
825 | // Current noise-spectrum.
826 | memset(self->noise, 0, sizeof(float) * HALF_ANAL_BLOCKL);
827 | // Previous noise-spectrum.
828 | memset(self->noisePrev, 0, sizeof(float) * HALF_ANAL_BLOCKL);
829 | // Conservative noise spectrum estimate.
830 | memset(self->magnAvgPause, 0, sizeof(float) * HALF_ANAL_BLOCKL);
831 | // For estimation of HB in second pass.
832 | memset(self->speechProb, 0, sizeof(float) * HALF_ANAL_BLOCKL);
833 | // Initial average magnitude spectrum.
834 | memset(self->initMagnEst, 0, sizeof(float) * HALF_ANAL_BLOCKL);
835 | for (i = 0; i < HALF_ANAL_BLOCKL; i++) {
836 | // Smooth LR (same as threshold).
837 | self->logLrtTimeAvg[i] = LRT_FEATURE_THR;
838 | }
839 |
840 | // Feature quantities.
841 | // Spectral flatness (start on threshold).
842 | self->featureData[0] = SF_FEATURE_THR;
843 | self->featureData[1] = 0.f; // Spectral entropy: not used in this version.
844 | self->featureData[2] = 0.f; // Spectral variance: not used in this version.
845 | // Average LRT factor (start on threshold).
846 | self->featureData[3] = LRT_FEATURE_THR;
847 | // Spectral template diff (start on threshold).
848 | self->featureData[4] = SF_FEATURE_THR;
849 | self->featureData[5] = 0.f; // Normalization for spectral difference.
850 | // Window time-average of input magnitude spectrum.
851 | self->featureData[6] = 0.f;
852 |
853 | // Histogram quantities: used to estimate/update thresholds for features.
854 | memset(self->histLrt, 0, sizeof(int) * HIST_PAR_EST);
855 | memset(self->histSpecFlat, 0, sizeof(int) * HIST_PAR_EST);
856 | memset(self->histSpecDiff, 0, sizeof(int) * HIST_PAR_EST);
857 |
858 |
859 | self->blockInd = -1; // Frame counter.
860 | // Default threshold for LRT feature.
861 | self->priorModelPars[0] = LRT_FEATURE_THR;
862 | // Threshold for spectral flatness: determined on-line.
863 | self->priorModelPars[1] = 0.5f;
864 | // sgn_map par for spectral measure: 1 for flatness measure.
865 | self->priorModelPars[2] = 1.f;
866 | // Threshold for template-difference feature: determined on-line.
867 | self->priorModelPars[3] = 0.5f;
868 | // Default weighting parameter for LRT feature.
869 | self->priorModelPars[4] = 1.f;
870 | // Default weighting parameter for spectral flatness feature.
871 | self->priorModelPars[5] = 0.f;
872 | // Default weighting parameter for spectral difference feature.
873 | self->priorModelPars[6] = 0.f;
874 |
875 | // Update flag for parameters:
876 | // 0 no update, 1 = update once, 2 = update every window.
877 | self->modelUpdatePars[0] = 2;
878 | self->modelUpdatePars[1] = 500; // Window for update.
879 | // Counter for update of conservative noise spectrum.
880 | self->modelUpdatePars[2] = 0;
881 | // Counter if the feature thresholds are updated during the sequence.
882 | self->modelUpdatePars[3] = self->modelUpdatePars[1];
883 |
884 | self->signalEnergy = 0.0;
885 | self->sumMagn = 0.0;
886 | self->whiteNoiseLevel = 0.0;
887 | self->pinkNoiseNumerator = 0.0;
888 | self->pinkNoiseExp = 0.0;
889 |
890 | set_feature_extraction_parameters(self);
891 |
892 | // Default mode.
893 | WebRtcNs_set_policy_core(self, 0);
894 |
895 | self->initFlag = 1;
896 | return 0;
897 | }
898 |
899 | // Estimate noise.
900 | static void NoiseEstimation(NoiseSuppressionC *self,
901 | float *magn,
902 | float *noise) {
903 | size_t i, s, offset = 0;
904 | float lmagn[HALF_ANAL_BLOCKL], delta;
905 |
906 | if (self->updates < END_STARTUP_LONG) {
907 | self->updates++;
908 | }
909 |
910 | for (i = 0; i < self->magnLen; i++) {
911 | lmagn[i] = logf(magn[i]);
912 | }
913 |
914 | // Loop over simultaneous estimates.
915 | for (s = 0; s < SIMULT; s++) {
916 | offset = s * self->magnLen;
917 |
918 | // newquantest(...)
919 | for (i = 0; i < self->magnLen; i++) {
920 | // Compute delta.
921 | if (self->density[offset + i] > 1.0) {
922 | delta = FACTOR * 1.f / self->density[offset + i];
923 | } else {
924 | delta = FACTOR;
925 | }
926 |
927 | // Update log quantile estimate.
928 | if (lmagn[i] > self->lquantile[offset + i]) {
929 | self->lquantile[offset + i] +=
930 | QUANTILE * delta / (float) (self->counter[s] + 1);
931 | } else {
932 | self->lquantile[offset + i] -=
933 | (1.f - QUANTILE) * delta / (float) (self->counter[s] + 1);
934 | }
935 |
936 | // Update density estimate.
937 | if (fabsf(lmagn[i] - self->lquantile[offset + i]) < WIDTH) {
938 | self->density[offset + i] =
939 | ((float) self->counter[s] * self->density[offset + i] +
940 | 1.f / (2.f * WIDTH)) /
941 | (float) (self->counter[s] + 1);
942 | }
943 | } // End loop over magnitude spectrum.
944 |
945 | if (self->counter[s] >= END_STARTUP_LONG) {
946 | self->counter[s] = 0;
947 | if (self->updates >= END_STARTUP_LONG) {
948 | for (i = 0; i < self->magnLen; i++) {
949 | self->quantile[i] = expf(self->lquantile[offset + i]);
950 | }
951 | }
952 | }
953 |
954 | self->counter[s]++;
955 | } // End loop over simultaneous estimates.
956 |
957 | // Sequentially update the noise during startup.
958 | if (self->updates < END_STARTUP_LONG) {
959 | // Use the last "s" to get noise during startup that differ from zero.
960 | for (i = 0; i < self->magnLen; i++) {
961 | self->quantile[i] = expf(self->lquantile[offset + i]);
962 | }
963 | }
964 |
965 | for (i = 0; i < self->magnLen; i++) {
966 | noise[i] = self->quantile[i];
967 | }
968 | }
969 |
970 | // Extract thresholds for feature parameters.
971 | // Histograms are computed over some window size (given by
972 | // self->modelUpdatePars[1]).
973 | // Thresholds and weights are extracted every window.
974 | // |flag| = 0 updates histogram only, |flag| = 1 computes the threshold/weights.
975 | // Threshold and weights are returned in: self->priorModelPars.
976 | static void FeatureParameterExtraction(NoiseSuppressionC *self, int flag) {
977 | int i, useFeatureSpecFlat, useFeatureSpecDiff, numHistLrt;
978 | int maxPeak1, maxPeak2;
979 | int weightPeak1SpecFlat, weightPeak2SpecFlat, weightPeak1SpecDiff,
980 | weightPeak2SpecDiff;
981 |
982 | float binMid, featureSum;
983 | float posPeak1SpecFlat, posPeak2SpecFlat, posPeak1SpecDiff, posPeak2SpecDiff;
984 | float fluctLrt, avgHistLrt, avgSquareHistLrt, avgHistLrtCompl;
985 |
986 | // 3 features: LRT, flatness, difference.
987 | // lrt_feature = self->featureData[3];
988 | // flat_feature = self->featureData[0];
989 | // diff_feature = self->featureData[4];
990 |
991 | // Update histograms.
992 | if (flag == 0) {
993 | // LRT
994 | if ((self->featureData[3] <
995 | HIST_PAR_EST * self->featureExtractionParams.binSizeLrt) &&
996 | (self->featureData[3] >= 0.0)) {
997 | i = (int) (self->featureData[3] /
998 | self->featureExtractionParams.binSizeLrt);
999 | self->histLrt[i]++;
1000 | }
1001 | // Spectral flatness.
1002 | if ((self->featureData[0] <
1003 | HIST_PAR_EST * self->featureExtractionParams.binSizeSpecFlat) &&
1004 | (self->featureData[0] >= 0.0)) {
1005 | i = (int) (self->featureData[0] /
1006 | self->featureExtractionParams.binSizeSpecFlat);
1007 | self->histSpecFlat[i]++;
1008 | }
1009 | // Spectral difference.
1010 | if ((self->featureData[4] <
1011 | HIST_PAR_EST * self->featureExtractionParams.binSizeSpecDiff) &&
1012 | (self->featureData[4] >= 0.0)) {
1013 | i = (int) (self->featureData[4] /
1014 | self->featureExtractionParams.binSizeSpecDiff);
1015 | self->histSpecDiff[i]++;
1016 | }
1017 | }
1018 |
1019 | // Extract parameters for speech/noise probability.
1020 | if (flag == 1) {
1021 | // LRT feature: compute the average over
1022 | // self->featureExtractionParams.rangeAvgHistLrt.
1023 | avgHistLrt = 0.0;
1024 | avgHistLrtCompl = 0.0;
1025 | avgSquareHistLrt = 0.0;
1026 | numHistLrt = 0;
1027 | for (i = 0; i < HIST_PAR_EST; i++) {
1028 | binMid = ((float) i + 0.5f) * self->featureExtractionParams.binSizeLrt;
1029 | if (binMid <= self->featureExtractionParams.rangeAvgHistLrt) {
1030 | avgHistLrt += self->histLrt[i] * binMid;
1031 | numHistLrt += self->histLrt[i];
1032 | }
1033 | avgSquareHistLrt += self->histLrt[i] * binMid * binMid;
1034 | avgHistLrtCompl += self->histLrt[i] * binMid;
1035 | }
1036 | if (numHistLrt > 0) {
1037 | avgHistLrt = avgHistLrt / ((float) numHistLrt);
1038 | }
1039 | avgHistLrtCompl = avgHistLrtCompl / ((float) self->modelUpdatePars[1]);
1040 | avgSquareHistLrt = avgSquareHistLrt / ((float) self->modelUpdatePars[1]);
1041 | fluctLrt = avgSquareHistLrt - avgHistLrt * avgHistLrtCompl;
1042 | // Get threshold for LRT feature.
1043 | if (fluctLrt < self->featureExtractionParams.thresFluctLrt) {
1044 | // Very low fluctuation, so likely noise.
1045 | self->priorModelPars[0] = self->featureExtractionParams.maxLrt;
1046 | } else {
1047 | self->priorModelPars[0] =
1048 | self->featureExtractionParams.factor1ModelPars * avgHistLrt;
1049 | // Check if value is within min/max range.
1050 | if (self->priorModelPars[0] < self->featureExtractionParams.minLrt) {
1051 | self->priorModelPars[0] = self->featureExtractionParams.minLrt;
1052 | }
1053 | if (self->priorModelPars[0] > self->featureExtractionParams.maxLrt) {
1054 | self->priorModelPars[0] = self->featureExtractionParams.maxLrt;
1055 | }
1056 | }
1057 | // Done with LRT feature.
1058 |
1059 | // For spectral flatness and spectral difference: compute the main peaks of
1060 | // histogram.
1061 | maxPeak1 = 0;
1062 | maxPeak2 = 0;
1063 | posPeak1SpecFlat = 0.0;
1064 | posPeak2SpecFlat = 0.0;
1065 | weightPeak1SpecFlat = 0;
1066 | weightPeak2SpecFlat = 0;
1067 |
1068 | // Peaks for flatness.
1069 | for (i = 0; i < HIST_PAR_EST; i++) {
1070 | binMid =
1071 | (i + 0.5f) * self->featureExtractionParams.binSizeSpecFlat;
1072 | if (self->histSpecFlat[i] > maxPeak1) {
1073 | // Found new "first" peak.
1074 | maxPeak2 = maxPeak1;
1075 | weightPeak2SpecFlat = weightPeak1SpecFlat;
1076 | posPeak2SpecFlat = posPeak1SpecFlat;
1077 |
1078 | maxPeak1 = self->histSpecFlat[i];
1079 | weightPeak1SpecFlat = self->histSpecFlat[i];
1080 | posPeak1SpecFlat = binMid;
1081 | } else if (self->histSpecFlat[i] > maxPeak2) {
1082 | // Found new "second" peak.
1083 | maxPeak2 = self->histSpecFlat[i];
1084 | weightPeak2SpecFlat = self->histSpecFlat[i];
1085 | posPeak2SpecFlat = binMid;
1086 | }
1087 | }
1088 |
1089 | // Compute two peaks for spectral difference.
1090 | maxPeak1 = 0;
1091 | maxPeak2 = 0;
1092 | posPeak1SpecDiff = 0.0;
1093 | posPeak2SpecDiff = 0.0;
1094 | weightPeak1SpecDiff = 0;
1095 | weightPeak2SpecDiff = 0;
1096 | // Peaks for spectral difference.
1097 | for (i = 0; i < HIST_PAR_EST; i++) {
1098 | binMid =
1099 | ((float) i + 0.5f) * self->featureExtractionParams.binSizeSpecDiff;
1100 | if (self->histSpecDiff[i] > maxPeak1) {
1101 | // Found new "first" peak.
1102 | maxPeak2 = maxPeak1;
1103 | weightPeak2SpecDiff = weightPeak1SpecDiff;
1104 | posPeak2SpecDiff = posPeak1SpecDiff;
1105 |
1106 | maxPeak1 = self->histSpecDiff[i];
1107 | weightPeak1SpecDiff = self->histSpecDiff[i];
1108 | posPeak1SpecDiff = binMid;
1109 | } else if (self->histSpecDiff[i] > maxPeak2) {
1110 | // Found new "second" peak.
1111 | maxPeak2 = self->histSpecDiff[i];
1112 | weightPeak2SpecDiff = self->histSpecDiff[i];
1113 | posPeak2SpecDiff = binMid;
1114 | }
1115 | }
1116 |
1117 | // For spectrum flatness feature.
1118 | useFeatureSpecFlat = 1;
1119 | // Merge the two peaks if they are close.
1120 | if ((fabsf(posPeak2SpecFlat - posPeak1SpecFlat) <
1121 | self->featureExtractionParams.limitPeakSpacingSpecFlat) &&
1122 | (weightPeak2SpecFlat >
1123 | self->featureExtractionParams.limitPeakWeightsSpecFlat *
1124 | weightPeak1SpecFlat)) {
1125 | weightPeak1SpecFlat += weightPeak2SpecFlat;
1126 | posPeak1SpecFlat = 0.5f * (posPeak1SpecFlat + posPeak2SpecFlat);
1127 | }
1128 | // Reject if weight of peaks is not large enough, or peak value too small.
1129 | if (weightPeak1SpecFlat <
1130 | self->featureExtractionParams.thresWeightSpecFlat ||
1131 | posPeak1SpecFlat < self->featureExtractionParams.thresPosSpecFlat) {
1132 | useFeatureSpecFlat = 0;
1133 | }
1134 | // If selected, get the threshold.
1135 | if (useFeatureSpecFlat == 1) {
1136 | // Compute the threshold.
1137 | self->priorModelPars[1] =
1138 | self->featureExtractionParams.factor2ModelPars * posPeak1SpecFlat;
1139 | // Check if value is within min/max range.
1140 | if (self->priorModelPars[1] < self->featureExtractionParams.minSpecFlat) {
1141 | self->priorModelPars[1] = self->featureExtractionParams.minSpecFlat;
1142 | }
1143 | if (self->priorModelPars[1] > self->featureExtractionParams.maxSpecFlat) {
1144 | self->priorModelPars[1] = self->featureExtractionParams.maxSpecFlat;
1145 | }
1146 | }
1147 | // Done with flatness feature.
1148 |
1149 | // For template feature.
1150 | useFeatureSpecDiff = 1;
1151 | // Merge the two peaks if they are close.
1152 | if ((fabsf(posPeak2SpecDiff - posPeak1SpecDiff) <
1153 | self->featureExtractionParams.limitPeakSpacingSpecDiff) &&
1154 | (weightPeak2SpecDiff >
1155 | self->featureExtractionParams.limitPeakWeightsSpecDiff *
1156 | weightPeak1SpecDiff)) {
1157 | weightPeak1SpecDiff += weightPeak2SpecDiff;
1158 | posPeak1SpecDiff = 0.5f * (posPeak1SpecDiff + posPeak2SpecDiff);
1159 | }
1160 | // Get the threshold value.
1161 | self->priorModelPars[3] =
1162 | self->featureExtractionParams.factor1ModelPars * posPeak1SpecDiff;
1163 | // Reject if weight of peaks is not large enough.
1164 | if (weightPeak1SpecDiff <
1165 | self->featureExtractionParams.thresWeightSpecDiff) {
1166 | useFeatureSpecDiff = 0;
1167 | }
1168 | // Check if value is within min/max range.
1169 | if (self->priorModelPars[3] < self->featureExtractionParams.minSpecDiff) {
1170 | self->priorModelPars[3] = self->featureExtractionParams.minSpecDiff;
1171 | }
1172 | if (self->priorModelPars[3] > self->featureExtractionParams.maxSpecDiff) {
1173 | self->priorModelPars[3] = self->featureExtractionParams.maxSpecDiff;
1174 | }
1175 | // Done with spectral difference feature.
1176 |
1177 | // Don't use template feature if fluctuation of LRT feature is very low:
1178 | // most likely just noise state.
1179 | if (fluctLrt < self->featureExtractionParams.thresFluctLrt) {
1180 | useFeatureSpecDiff = 0;
1181 | }
1182 |
1183 | // Select the weights between the features.
1184 | // self->priorModelPars[4] is weight for LRT: always selected.
1185 | // self->priorModelPars[5] is weight for spectral flatness.
1186 | // self->priorModelPars[6] is weight for spectral difference.
1187 | featureSum = (float) (1 + useFeatureSpecFlat + useFeatureSpecDiff);
1188 | self->priorModelPars[4] = 1.f / featureSum;
1189 | self->priorModelPars[5] = ((float) useFeatureSpecFlat) / featureSum;
1190 | self->priorModelPars[6] = ((float) useFeatureSpecDiff) / featureSum;
1191 |
1192 | // Set hists to zero for next update.
1193 | if (self->modelUpdatePars[0] >= 1) {
1194 | for (i = 0; i < HIST_PAR_EST; i++) {
1195 | self->histLrt[i] = 0;
1196 | self->histSpecFlat[i] = 0;
1197 | self->histSpecDiff[i] = 0;
1198 | }
1199 | }
1200 | } // End of flag == 1.
1201 | }
1202 |
1203 | // Compute spectral flatness on input spectrum.
1204 | // |magnIn| is the magnitude spectrum.
1205 | // Spectral flatness is returned in self->featureData[0].
1206 | static void ComputeSpectralFlatness(NoiseSuppressionC *self,
1207 | const float *magnIn) {
1208 | size_t i;
1209 | size_t shiftLP = 1; // Option to remove first bin(s) from spectral measures.
1210 | float avgSpectralFlatnessNum, avgSpectralFlatnessDen, spectralTmp;
1211 |
1212 | // Compute spectral measures.
1213 | // For flatness.
1214 | avgSpectralFlatnessNum = 0.0;
1215 | avgSpectralFlatnessDen = self->sumMagn;
1216 | for (i = 0; i < shiftLP; i++) {
1217 | avgSpectralFlatnessDen -= magnIn[i];
1218 | }
1219 | // Compute log of ratio of the geometric to arithmetic mean: check for log(0)
1220 | // case.
1221 | for (i = shiftLP; i < self->magnLen; i++) {
1222 | if (magnIn[i] > 0.0) {
1223 | avgSpectralFlatnessNum += logf(magnIn[i]);
1224 | } else {
1225 | self->featureData[0] -= SPECT_FL_TAVG * self->featureData[0];
1226 | return;
1227 | }
1228 | }
1229 | // Normalize.
1230 | avgSpectralFlatnessDen = avgSpectralFlatnessDen / self->magnLen;
1231 | avgSpectralFlatnessNum = avgSpectralFlatnessNum / self->magnLen;
1232 |
1233 | // Ratio and inverse log: check for case of log(0).
1234 | spectralTmp = expf(avgSpectralFlatnessNum) / avgSpectralFlatnessDen;
1235 |
1236 | // Time-avg update of spectral flatness feature.
1237 | self->featureData[0] += SPECT_FL_TAVG * (spectralTmp - self->featureData[0]);
1238 | // Done with flatness feature.
1239 | }
1240 |
1241 | // Compute prior and post SNR based on quantile noise estimation.
1242 | // Compute DD estimate of prior SNR.
1243 | // Inputs:
1244 | // * |magn| is the signal magnitude spectrum estimate.
1245 | // * |noise| is the magnitude noise spectrum estimate.
1246 | // Outputs:
1247 | // * |snrLocPrior| is the computed prior SNR.
1248 | // * |snrLocPost| is the computed post SNR.
1249 | static void ComputeSnr(const NoiseSuppressionC *self,
1250 | const float *magn,
1251 | const float *noise,
1252 | float *snrLocPrior,
1253 | float *snrLocPost) {
1254 | size_t i;
1255 |
1256 | for (i = 0; i < self->magnLen; i++) {
1257 | // Previous post SNR.
1258 | // Previous estimate: based on previous frame with gain filter.
1259 | float previousEstimateStsa = self->magnPrevAnalyze[i] /
1260 | (self->noisePrev[i] + 0.0001f) * self->smooth[i];
1261 | // Post SNR.
1262 | snrLocPost[i] = 0.f;
1263 | if (magn[i] > noise[i]) {
1264 | snrLocPost[i] = magn[i] / (noise[i] + 0.0001f) - 1.f;
1265 | }
1266 | // DD estimate is sum of two terms: current estimate and previous estimate.
1267 | // Directed decision update of snrPrior.
1268 | snrLocPrior[i] =
1269 | DD_PR_SNR * previousEstimateStsa + (1.f - DD_PR_SNR) * snrLocPost[i];
1270 | } // End of loop over frequencies.
1271 | }
1272 |
1273 | // Compute the difference measure between input spectrum and a template/learned
1274 | // noise spectrum.
1275 | // |magnIn| is the input spectrum.
1276 | // The reference/template spectrum is self->magnAvgPause[i].
1277 | // Returns (normalized) spectral difference in self->featureData[4].
1278 | static void ComputeSpectralDifference(NoiseSuppressionC *self,
1279 | const float *magnIn) {
1280 | // avgDiffNormMagn = var(magnIn) - cov(magnIn, magnAvgPause)^2 /
1281 | // var(magnAvgPause)
1282 | size_t i;
1283 | float avgPause, avgMagn, covMagnPause, varPause, varMagn, avgDiffNormMagn;
1284 |
1285 | avgPause = 0.0;
1286 | avgMagn = self->sumMagn;
1287 | // Compute average quantities.
1288 | for (i = 0; i < self->magnLen; i++) {
1289 | // Conservative smooth noise spectrum from pause frames.
1290 | avgPause += self->magnAvgPause[i];
1291 | }
1292 | avgPause /= self->magnLen;
1293 | avgMagn /= self->magnLen;
1294 |
1295 | covMagnPause = 0.0;
1296 | varPause = 0.0;
1297 | varMagn = 0.0;
1298 | // Compute variance and covariance quantities.
1299 | for (i = 0; i < self->magnLen; i++) {
1300 | covMagnPause += (magnIn[i] - avgMagn) * (self->magnAvgPause[i] - avgPause);
1301 | varPause +=
1302 | (self->magnAvgPause[i] - avgPause) * (self->magnAvgPause[i] - avgPause);
1303 | varMagn += (magnIn[i] - avgMagn) * (magnIn[i] - avgMagn);
1304 | }
1305 | covMagnPause /= self->magnLen;
1306 | varPause /= self->magnLen;
1307 | varMagn /= self->magnLen;
1308 | // Update of average magnitude spectrum.
1309 | self->featureData[6] += self->signalEnergy;
1310 |
1311 | avgDiffNormMagn =
1312 | varMagn - (covMagnPause * covMagnPause) / (varPause + 0.0001f);
1313 | // Normalize and compute time-avg update of difference feature.
1314 | avgDiffNormMagn = avgDiffNormMagn / (self->featureData[5] + 0.0001f);
1315 | self->featureData[4] +=
1316 | SPECT_DIFF_TAVG * (avgDiffNormMagn - self->featureData[4]);
1317 | }
1318 |
1319 | // Compute speech/noise probability.
1320 | // Speech/noise probability is returned in |probSpeechFinal|.
1321 | // |magn| is the input magnitude spectrum.
1322 | // |noise| is the noise spectrum.
1323 | // |snrLocPrior| is the prior SNR for each frequency.
1324 | // |snrLocPost| is the post SNR for each frequency.
1325 | static void SpeechNoiseProb(NoiseSuppressionC *self,
1326 | float *probSpeechFinal,
1327 | const float *snrLocPrior,
1328 | const float *snrLocPost) {
1329 | size_t i;
1330 | int sgnMap;
1331 | float invLrt, gainPrior, indPrior;
1332 | float logLrtTimeAvgKsum, besselTmp;
1333 | float indicator0, indicator1, indicator2;
1334 | float tmpFloat1, tmpFloat2;
1335 | float weightIndPrior0, weightIndPrior1, weightIndPrior2;
1336 | float threshPrior0, threshPrior1, threshPrior2;
1337 | float widthPrior, widthPrior0, widthPrior1, widthPrior2;
1338 |
1339 | widthPrior0 = WIDTH_PR_MAP;
1340 | // Width for pause region: lower range, so increase width in tanh map.
1341 | widthPrior1 = 2.f * WIDTH_PR_MAP;
1342 | widthPrior2 = 2.f * WIDTH_PR_MAP; // For spectral-difference measure.
1343 |
1344 | // Threshold parameters for features.
1345 | threshPrior0 = self->priorModelPars[0];
1346 | threshPrior1 = self->priorModelPars[1];
1347 | threshPrior2 = self->priorModelPars[3];
1348 |
1349 | // Sign for flatness feature.
1350 | sgnMap = (int) (self->priorModelPars[2]);
1351 |
1352 | // Weight parameters for features.
1353 | weightIndPrior0 = self->priorModelPars[4];
1354 | weightIndPrior1 = self->priorModelPars[5];
1355 | weightIndPrior2 = self->priorModelPars[6];
1356 |
1357 | // Compute feature based on average LR factor.
1358 | // This is the average over all frequencies of the smooth log LRT.
1359 | logLrtTimeAvgKsum = 0.0;
1360 | for (i = 0; i < self->magnLen; i++) {
1361 | tmpFloat1 = 1.f + 2.f * snrLocPrior[i];
1362 | tmpFloat2 = 2.f * snrLocPrior[i] / (tmpFloat1 + 0.0001f);
1363 | besselTmp = (snrLocPost[i] + 1.f) * tmpFloat2;
1364 | self->logLrtTimeAvg[i] +=
1365 | LRT_TAVG * (besselTmp - logf(tmpFloat1) - self->logLrtTimeAvg[i]);
1366 | logLrtTimeAvgKsum += self->logLrtTimeAvg[i];
1367 | }
1368 | logLrtTimeAvgKsum = logLrtTimeAvgKsum / (self->magnLen);
1369 | self->featureData[3] = logLrtTimeAvgKsum;
1370 | // Done with computation of LR factor.
1371 |
1372 | // Compute the indicator functions.
1373 | // Average LRT feature.
1374 | widthPrior = widthPrior0;
1375 | // Use larger width in tanh map for pause regions.
1376 | if (logLrtTimeAvgKsum < threshPrior0) {
1377 | widthPrior = widthPrior1;
1378 | }
1379 | // Compute indicator function: sigmoid map.
1380 | indicator0 =
1381 | 0.5f *
1382 | (tanhf(widthPrior * (logLrtTimeAvgKsum - threshPrior0)) + 1.f);
1383 |
1384 | // Spectral flatness feature.
1385 | tmpFloat1 = self->featureData[0];
1386 | widthPrior = widthPrior0;
1387 | // Use larger width in tanh map for pause regions.
1388 | if (sgnMap == 1 && (tmpFloat1 > threshPrior1)) {
1389 | widthPrior = widthPrior1;
1390 | }
1391 | if (sgnMap == -1 && (tmpFloat1 < threshPrior1)) {
1392 | widthPrior = widthPrior1;
1393 | }
1394 | // Compute indicator function: sigmoid map.
1395 | indicator1 =
1396 | 0.5f *
1397 | (tanhf((float) sgnMap * widthPrior * (threshPrior1 - tmpFloat1)) +
1398 | 1.f);
1399 |
1400 | // For template spectrum-difference.
1401 | tmpFloat1 = self->featureData[4];
1402 | widthPrior = widthPrior0;
1403 | // Use larger width in tanh map for pause regions.
1404 | if (tmpFloat1 < threshPrior2) {
1405 | widthPrior = widthPrior2;
1406 | }
1407 | // Compute indicator function: sigmoid map.
1408 | indicator2 =
1409 | 0.5f * (tanhf(widthPrior * (tmpFloat1 - threshPrior2)) + 1.f);
1410 |
1411 | // Combine the indicator function with the feature weights.
1412 | indPrior = weightIndPrior0 * indicator0 + weightIndPrior1 * indicator1 +
1413 | weightIndPrior2 * indicator2;
1414 | // Done with computing indicator function.
1415 |
1416 | // Compute the prior probability.
1417 | self->priorSpeechProb += PRIOR_UPDATE * (indPrior - self->priorSpeechProb);
1418 | // Make sure probabilities are within range: keep floor to 0.01.
1419 | if (self->priorSpeechProb > 1.f) {
1420 | self->priorSpeechProb = 1.f;
1421 | }
1422 | if (self->priorSpeechProb < 0.01f) {
1423 | self->priorSpeechProb = 0.01f;
1424 | }
1425 |
1426 | // Final speech probability: combine prior model with LR factor:.
1427 | gainPrior = (1.f - self->priorSpeechProb) / (self->priorSpeechProb + 0.0001f);
1428 | for (i = 0; i < self->magnLen; i++) {
1429 | invLrt = expf(-self->logLrtTimeAvg[i]);
1430 | invLrt = gainPrior * invLrt;
1431 | probSpeechFinal[i] = 1.f / (1.f + invLrt);
1432 | }
1433 | }
1434 |
1435 | // Update the noise features.
1436 | // Inputs:
1437 | // * |magn| is the signal magnitude spectrum estimate.
1438 | // * |updateParsFlag| is an update flag for parameters.
1439 | static void FeatureUpdate(NoiseSuppressionC *self,
1440 | const float *magn,
1441 | int updateParsFlag) {
1442 | // Compute spectral flatness on input spectrum.
1443 | ComputeSpectralFlatness(self, magn);
1444 | // Compute difference of input spectrum with learned/estimated noise spectrum.
1445 | ComputeSpectralDifference(self, magn);
1446 | // Compute histograms for parameter decisions (thresholds and weights for
1447 | // features).
1448 | // Parameters are extracted once every window time.
1449 | // (=self->modelUpdatePars[1])
1450 | if (updateParsFlag >= 1) {
1451 | // Counter update.
1452 | self->modelUpdatePars[3]--;
1453 | // Update histogram.
1454 | if (self->modelUpdatePars[3] > 0) {
1455 | FeatureParameterExtraction(self, 0);
1456 | }
1457 | // Compute model parameters.
1458 | if (self->modelUpdatePars[3] == 0) {
1459 | FeatureParameterExtraction(self, 1);
1460 | self->modelUpdatePars[3] = self->modelUpdatePars[1];
1461 | // If wish to update only once, set flag to zero.
1462 | if (updateParsFlag == 1) {
1463 | self->modelUpdatePars[0] = 0;
1464 | } else {
1465 | // Update every window:
1466 | // Get normalization for spectral difference for next window estimate.
1467 | self->featureData[6] =
1468 | self->featureData[6] / ((float) self->modelUpdatePars[1]);
1469 | self->featureData[5] =
1470 | 0.5f * (self->featureData[6] + self->featureData[5]);
1471 | self->featureData[6] = 0.f;
1472 | }
1473 | }
1474 | }
1475 | }
1476 |
1477 | // Update the noise estimate.
1478 | // Inputs:
1479 | // * |magn| is the signal magnitude spectrum estimate.
1480 | // * |snrLocPrior| is the prior SNR.
1481 | // * |snrLocPost| is the post SNR.
1482 | // Output:
1483 | // * |noise| is the updated noise magnitude spectrum estimate.
1484 | static void UpdateNoiseEstimate(NoiseSuppressionC *self,
1485 | const float *magn,
1486 | float *noise) {
1487 | size_t i;
1488 | float probSpeech, probNonSpeech;
1489 | // Time-avg parameter for noise update.
1490 | float gammaNoiseTmp = NOISE_UPDATE;
1491 | float gammaNoiseOld;
1492 | float noiseUpdateTmp;
1493 |
1494 | for (i = 0; i < self->magnLen; i++) {
1495 | probSpeech = self->speechProb[i];
1496 | probNonSpeech = 1.f - probSpeech;
1497 | // Temporary noise update:
1498 | // Use it for speech frames if update value is less than previous.
1499 | noiseUpdateTmp = gammaNoiseTmp * self->noisePrev[i] +
1500 | (1.f - gammaNoiseTmp) * (probNonSpeech * magn[i] +
1501 | probSpeech * self->noisePrev[i]);
1502 | // Time-constant based on speech/noise state.
1503 | gammaNoiseOld = gammaNoiseTmp;
1504 | gammaNoiseTmp = NOISE_UPDATE;
1505 | // Increase gamma (i.e., less noise update) for frame likely to be speech.
1506 | if (probSpeech > PROB_RANGE) {
1507 | gammaNoiseTmp = SPEECH_UPDATE;
1508 | }
1509 | // Conservative noise update.
1510 | if (probSpeech < PROB_RANGE) {
1511 | self->magnAvgPause[i] += GAMMA_PAUSE * (magn[i] - self->magnAvgPause[i]);
1512 | }
1513 | // Noise update.
1514 | if (gammaNoiseTmp == gammaNoiseOld) {
1515 | noise[i] = noiseUpdateTmp;
1516 | } else {
1517 | noise[i] = gammaNoiseTmp * self->noisePrev[i] +
1518 | (1.f - gammaNoiseTmp) * (probNonSpeech * magn[i] +
1519 | probSpeech * self->noisePrev[i]);
1520 | // Allow for noise update downwards:
1521 | // If noise update decreases the noise, it is safe, so allow it to
1522 | // happen.
1523 | if (noiseUpdateTmp < noise[i]) {
1524 | noise[i] = noiseUpdateTmp;
1525 | }
1526 | }
1527 | } // End of freq loop.
1528 | }
1529 |
1530 | // Updates |buffer| with a new |frame|.
1531 | // Inputs:
1532 | // * |frame| is a new speech frame or NULL for setting to zero.
1533 | // * |frame_length| is the length of the new frame.
1534 | // * |buffer_length| is the length of the buffer.
1535 | // Output:
1536 | // * |buffer| is the updated buffer.
1537 | static void UpdateBuffer(const int16_t *frame,
1538 | size_t frame_length,
1539 | size_t buffer_length,
1540 | float *buffer) {
1541 | assert(buffer_length < 2 * frame_length);
1542 |
1543 | memcpy(buffer,
1544 | buffer + frame_length,
1545 | sizeof(*buffer) * (buffer_length - frame_length));
1546 | if (frame) {
1547 | for (int i = 0; i < frame_length; ++i) {
1548 | buffer[buffer_length - frame_length + i] = frame[i];
1549 | }
1550 | } else {
1551 | memset(buffer + buffer_length - frame_length,
1552 | 0,
1553 | sizeof(*buffer) * frame_length);
1554 | }
1555 | }
1556 |
1557 | // Transforms the signal from time to frequency domain.
1558 | // Inputs:
1559 | // * |time_data| is the signal in the time domain.
1560 | // * |time_data_length| is the length of the analysis buffer.
1561 | // * |magnitude_length| is the length of the spectrum magnitude, which equals
1562 | // the length of both |real| and |imag| (time_data_length / 2 + 1).
1563 | // Outputs:
1564 | // * |time_data| is the signal in the frequency domain.
1565 | // * |real| is the real part of the frequency domain.
1566 | // * |imag| is the imaginary part of the frequency domain.
1567 | // * |magn| is the calculated signal magnitude in the frequency domain.
1568 | static void FFT(NoiseSuppressionC *self,
1569 | float *time_data,
1570 | size_t time_data_length,
1571 | size_t magnitude_length,
1572 | float *real,
1573 | float *imag,
1574 | float *magn) {
1575 | size_t i;
1576 |
1577 | assert(magnitude_length == time_data_length / 2 + 1);
1578 |
1579 | WebRtc_rdft(time_data_length, 1, time_data, self->ip, self->wfft);
1580 |
1581 | imag[0] = 0;
1582 | real[0] = time_data[0];
1583 | magn[0] = fabsf(real[0]) + 1.f;
1584 | imag[magnitude_length - 1] = 0;
1585 | real[magnitude_length - 1] = time_data[1];
1586 | magn[magnitude_length - 1] = fabsf(real[magnitude_length - 1]) + 1.f;
1587 | for (i = 1; i < magnitude_length - 1; ++i) {
1588 | real[i] = time_data[2 * i];
1589 | imag[i] = time_data[2 * i + 1];
1590 | // Magnitude spectrum.
1591 | magn[i] = sqrtf(real[i] * real[i] + imag[i] * imag[i]) + 1.f;
1592 | }
1593 | }
1594 |
1595 | // Transforms the signal from frequency to time domain.
1596 | // Inputs:
1597 | // * |real| is the real part of the frequency domain.
1598 | // * |imag| is the imaginary part of the frequency domain.
1599 | // * |magnitude_length| is the length of the spectrum magnitude, which equals
1600 | // the length of both |real| and |imag|.
1601 | // * |time_data_length| is the length of the analysis buffer
1602 | // (2 * (magnitude_length - 1)).
1603 | // Output:
1604 | // * |time_data| is the signal in the time domain.
1605 | static void IFFT(NoiseSuppressionC *self,
1606 | const float *real,
1607 | const float *imag,
1608 | size_t magnitude_length,
1609 | size_t time_data_length,
1610 | float *time_data) {
1611 | size_t i;
1612 |
1613 | assert(time_data_length == 2 * (magnitude_length - 1));
1614 |
1615 | time_data[0] = real[0];
1616 | time_data[1] = real[magnitude_length - 1];
1617 | for (i = 1; i < magnitude_length - 1; ++i) {
1618 | time_data[2 * i] = real[i];
1619 | time_data[2 * i + 1] = imag[i];
1620 | }
1621 | WebRtc_rdft(time_data_length, -1, time_data, self->ip, self->wfft);
1622 |
1623 | for (i = 0; i < time_data_length; ++i) {
1624 | time_data[i] *= 2.f / time_data_length; // FFT scaling.
1625 | }
1626 | }
1627 |
1628 | // Calculates the energy of a buffer.
1629 | // Inputs:
1630 | // * |buffer| is the buffer over which the energy is calculated.
1631 | // * |length| is the length of the buffer.
1632 | // Returns the calculated energy.
1633 | static float Energy(const float *buffer, size_t length) {
1634 | size_t i;
1635 | float energy = 0.f;
1636 |
1637 | for (i = 0; i < length; ++i) {
1638 | energy += buffer[i] * buffer[i];
1639 | }
1640 |
1641 | return energy;
1642 | }
1643 |
1644 | // Windows a buffer.
1645 | // Inputs:
1646 | // * |window| is the window by which to multiply.
1647 | // * |data| is the data without windowing.
1648 | // * |length| is the length of the window and data.
1649 | // Output:
1650 | // * |data_windowed| is the windowed data.
1651 | static void Windowing(const float *window,
1652 | const float *data,
1653 | size_t length,
1654 | float *data_windowed) {
1655 | size_t i;
1656 |
1657 | for (i = 0; i < length; ++i) {
1658 | data_windowed[i] = window[i] * data[i];
1659 | }
1660 | }
1661 |
1662 | // Estimate prior SNR decision-directed and compute DD based Wiener Filter.
1663 | // Input:
1664 | // * |magn| is the signal magnitude spectrum estimate.
1665 | // Output:
1666 | // * |theFilter| is the frequency response of the computed Wiener filter.
1667 | static void ComputeDdBasedWienerFilter(const NoiseSuppressionC *self,
1668 | const float *magn,
1669 | float *theFilter) {
1670 | size_t i;
1671 | float snrPrior, previousEstimateStsa, currentEstimateStsa;
1672 |
1673 | for (i = 0; i < self->magnLen; i++) {
1674 | // Previous estimate: based on previous frame with gain filter.
1675 | previousEstimateStsa = self->magnPrevProcess[i] /
1676 | (self->noisePrev[i] + 0.0001f) * self->smooth[i];
1677 | // Post and prior SNR.
1678 | currentEstimateStsa = 0.f;
1679 | if (magn[i] > self->noise[i]) {
1680 | currentEstimateStsa = magn[i] / (self->noise[i] + 0.0001f) - 1.f;
1681 | }
1682 | // DD estimate is sum of two terms: current estimate and previous estimate.
1683 | // Directed decision update of |snrPrior|.
1684 | snrPrior = DD_PR_SNR * previousEstimateStsa +
1685 | (1.f - DD_PR_SNR) * currentEstimateStsa;
1686 | // Gain filter.
1687 | theFilter[i] = snrPrior / (self->overdrive + snrPrior);
1688 | } // End of loop over frequencies.
1689 | }
1690 |
1691 | // Changes the aggressiveness of the noise suppression method.
1692 | // |mode| = 0 is mild (6dB), |mode| = 1 is medium (10dB) and |mode| = 2 is
1693 | // aggressive (15dB).
1694 | // Returns 0 on success and -1 otherwise.
1695 | int WebRtcNs_set_policy_core(NoiseSuppressionC *self, int mode) {
1696 | // Allow for modes: 0, 1, 2, 3.
1697 | if (mode == 0) {
1698 | self->overdrive = 1.f;
1699 | self->denoiseBound = 0.5f;
1700 | self->gainmap = 0;
1701 | } else if (mode == 1) {
1702 | // self->overdrive = 1.25f;
1703 | self->overdrive = 1.f;
1704 | self->denoiseBound = 0.25f;
1705 | self->gainmap = 1;
1706 | } else if (mode == 2) {
1707 | // self->overdrive = 1.25f;
1708 | self->overdrive = 1.1f;
1709 | self->denoiseBound = 0.125f;
1710 | self->gainmap = 1;
1711 | } else if (mode == 3) {
1712 | // self->overdrive = 1.3f;
1713 | self->overdrive = 1.25f;
1714 | self->denoiseBound = 0.09f;
1715 | self->gainmap = 1;
1716 | } else {
1717 | return -1;
1718 | }
1719 | self->aggrMode = mode;
1720 | return 0;
1721 | }
1722 |
1723 | void WebRtcNs_AnalyzeCore(NoiseSuppressionC *self, const int16_t *speechFrame) {
1724 | size_t i;
1725 | const size_t kStartBand = 5; // Skip first frequency bins during estimation.
1726 | int updateParsFlag;
1727 | float energy;
1728 | float signalEnergy = 0.f;
1729 | float sumMagn = 0.f;
1730 | float tmpFloat1, tmpFloat2, tmpFloat3;
1731 | float winData[ANAL_BLOCKL_MAX];
1732 | float magn[HALF_ANAL_BLOCKL], noise[HALF_ANAL_BLOCKL];
1733 | float snrLocPost[HALF_ANAL_BLOCKL], snrLocPrior[HALF_ANAL_BLOCKL];
1734 | float real[ANAL_BLOCKL_MAX], imag[HALF_ANAL_BLOCKL];
1735 | // Variables during startup.
1736 | float sum_log_i = 0.0;
1737 | float sum_log_i_square = 0.0;
1738 | float sum_log_magn = 0.0;
1739 | float sum_log_i_log_magn = 0.0;
1740 | float parametric_exp = 0.0;
1741 | float parametric_num = 0.0;
1742 |
1743 | // Check that initiation has been done.
1744 | assert(1 == self->initFlag);
1745 | updateParsFlag = self->modelUpdatePars[0];
1746 |
1747 | // Update analysis buffer for L band.
1748 | UpdateBuffer(speechFrame, self->blockLen, self->anaLen, self->analyzeBuf);
1749 |
1750 | Windowing(self->window, self->analyzeBuf, self->anaLen, winData);
1751 | energy = Energy(winData, self->anaLen);
1752 | if (energy == 0.0) {
1753 | // We want to avoid updating statistics in this case:
1754 | // Updating feature statistics when we have zeros only will cause
1755 | // thresholds to move towards zero signal situations. This in turn has the
1756 | // effect that once the signal is "turned on" (non-zero values) everything
1757 | // will be treated as speech and there is no noise suppression effect.
1758 | // Depending on the duration of the inactive signal it takes a
1759 | // considerable amount of time for the system to learn what is noise and
1760 | // what is speech.
1761 | return;
1762 | }
1763 |
1764 | self->blockInd++; // Update the block index only when we process a block.
1765 |
1766 | FFT(self, winData, self->anaLen, self->magnLen, real, imag, magn);
1767 |
1768 | for (i = 0; i < self->magnLen; i++) {
1769 | signalEnergy += real[i] * real[i] + imag[i] * imag[i];
1770 | sumMagn += magn[i];
1771 | if (self->blockInd < END_STARTUP_SHORT) {
1772 | if (i >= kStartBand) {
1773 | tmpFloat2 = logf((float) i);
1774 | sum_log_i += tmpFloat2;
1775 | sum_log_i_square += tmpFloat2 * tmpFloat2;
1776 | tmpFloat1 = logf(magn[i]);
1777 | sum_log_magn += tmpFloat1;
1778 | sum_log_i_log_magn += tmpFloat2 * tmpFloat1;
1779 | }
1780 | }
1781 | }
1782 | signalEnergy /= self->magnLen;
1783 | self->signalEnergy = signalEnergy;
1784 | self->sumMagn = sumMagn;
1785 |
1786 | // Quantile noise estimate.
1787 | NoiseEstimation(self, magn, noise);
1788 | // Compute simplified noise model during startup.
1789 | if (self->blockInd < END_STARTUP_SHORT) {
1790 | // Estimate White noise.
1791 | self->whiteNoiseLevel += sumMagn / self->magnLen * self->overdrive;
1792 | // Estimate Pink noise parameters.
1793 | tmpFloat1 = sum_log_i_square * (self->magnLen - kStartBand);
1794 | tmpFloat1 -= (sum_log_i * sum_log_i);
1795 | tmpFloat2 =
1796 | (sum_log_i_square * sum_log_magn - sum_log_i * sum_log_i_log_magn);
1797 | tmpFloat3 = tmpFloat2 / tmpFloat1;
1798 | // Constrain the estimated spectrum to be positive.
1799 | if (tmpFloat3 < 0.f) {
1800 | tmpFloat3 = 0.f;
1801 | }
1802 | self->pinkNoiseNumerator += tmpFloat3;
1803 | tmpFloat2 = (sum_log_i * sum_log_magn);
1804 | tmpFloat2 -= (self->magnLen - kStartBand) * sum_log_i_log_magn;
1805 | tmpFloat3 = tmpFloat2 / tmpFloat1;
1806 | // Constrain the pink noise power to be in the interval [0, 1].
1807 | if (tmpFloat3 < 0.f) {
1808 | tmpFloat3 = 0.f;
1809 | }
1810 | if (tmpFloat3 > 1.f) {
1811 | tmpFloat3 = 1.f;
1812 | }
1813 | self->pinkNoiseExp += tmpFloat3;
1814 |
1815 | // Calculate frequency independent parts of parametric noise estimate.
1816 | if (self->pinkNoiseExp > 0.f) {
1817 | // Use pink noise estimate.
1818 | parametric_num =
1819 | expf(self->pinkNoiseNumerator / (float) (self->blockInd + 1));
1820 | parametric_num *= (float) (self->blockInd + 1);
1821 | parametric_exp = self->pinkNoiseExp / (float) (self->blockInd + 1);
1822 | }
1823 | for (i = 0; i < self->magnLen; i++) {
1824 | // Estimate the background noise using the white and pink noise
1825 | // parameters.
1826 | if (self->pinkNoiseExp == 0.f) {
1827 | // Use white noise estimate.
1828 | self->parametricNoise[i] = self->whiteNoiseLevel;
1829 | } else {
1830 | // Use pink noise estimate.
1831 | float use_band = (float) (i < kStartBand ? kStartBand : i);
1832 | self->parametricNoise[i] =
1833 | parametric_num / powf(use_band, parametric_exp);
1834 | }
1835 | // Weight quantile noise with modeled noise.
1836 | noise[i] *= (self->blockInd);
1837 | tmpFloat2 =
1838 | self->parametricNoise[i] * (END_STARTUP_SHORT - self->blockInd);
1839 | noise[i] += (tmpFloat2 / (float) (self->blockInd + 1));
1840 | noise[i] /= END_STARTUP_SHORT;
1841 | }
1842 | }
1843 | // Compute average signal during END_STARTUP_LONG time:
1844 | // used to normalize spectral difference measure.
1845 | if (self->blockInd < END_STARTUP_LONG) {
1846 | self->featureData[5] *= self->blockInd;
1847 | self->featureData[5] += signalEnergy;
1848 | self->featureData[5] /= (self->blockInd + 1);
1849 | }
1850 |
1851 | // Post and prior SNR needed for SpeechNoiseProb.
1852 | ComputeSnr(self, magn, noise, snrLocPrior, snrLocPost);
1853 |
1854 | FeatureUpdate(self, magn, updateParsFlag);
1855 | SpeechNoiseProb(self, self->speechProb, snrLocPrior, snrLocPost);
1856 | UpdateNoiseEstimate(self, magn, noise);
1857 |
1858 | // Keep track of noise spectrum for next frame.
1859 | memcpy(self->noise, noise, sizeof(*noise) * self->magnLen);
1860 | memcpy(self->magnPrevAnalyze, magn, sizeof(*magn) * self->magnLen);
1861 | }
1862 |
1863 | void WebRtcNs_ProcessCore(NoiseSuppressionC *self,
1864 | const int16_t *const *speechFrame,
1865 | size_t num_bands,
1866 | int16_t *const *outFrame) {
1867 | // Main routine for noise reduction.
1868 | int flagHB = 0;
1869 | size_t i, j;
1870 |
1871 | float energy1, energy2, gain, factor, factor1, factor2;
1872 | float fout[BLOCKL_MAX];
1873 | float winData[ANAL_BLOCKL_MAX];
1874 | float magn[HALF_ANAL_BLOCKL];
1875 | float theFilter[HALF_ANAL_BLOCKL], theFilterTmp[HALF_ANAL_BLOCKL];
1876 | float real[ANAL_BLOCKL_MAX], imag[HALF_ANAL_BLOCKL];
1877 |
1878 | // SWB variables.
1879 | int deltaBweHB = 1;
1880 | int deltaGainHB = 1;
1881 | float decayBweHB = 1.0;
1882 | float gainMapParHB = 1.0;
1883 | float avgProbSpeechHB, avgProbSpeechHBTmp, avgFilterGainHB, gainModHB;
1884 | float sumMagnAnalyze, sumMagnProcess;
1885 |
1886 | // Check that initiation has been done.
1887 | assert(1 == self->initFlag);
1888 | assert(num_bands - 1 <= NUM_HIGH_BANDS_MAX);
1889 |
1890 | const int16_t *const *speechFrameHB = NULL;
1891 | int16_t *const *outFrameHB = NULL;
1892 | size_t num_high_bands = 0;
1893 | if (num_bands > 1) {
1894 | speechFrameHB = &speechFrame[1];
1895 | outFrameHB = &outFrame[1];
1896 | num_high_bands = num_bands - 1;
1897 | flagHB = 1;
1898 | // Range for averaging low band quantities for H band gain.
1899 | deltaBweHB = (int) self->magnLen / 4;
1900 | deltaGainHB = deltaBweHB;
1901 | }
1902 |
1903 | // Update analysis buffer for L band.
1904 | UpdateBuffer(speechFrame[0], self->blockLen, self->anaLen, self->dataBuf);
1905 |
1906 | if (flagHB == 1) {
1907 | // Update analysis buffer for H bands.
1908 | for (i = 0; i < num_high_bands; ++i) {
1909 | UpdateBuffer(speechFrameHB[i],
1910 | self->blockLen,
1911 | self->anaLen,
1912 | self->dataBufHB[i]);
1913 | }
1914 | }
1915 |
1916 | Windowing(self->window, self->dataBuf, self->anaLen, winData);
1917 | energy1 = Energy(winData, self->anaLen);
1918 | if (energy1 == 0.0) {
1919 | // Synthesize the special case of zero input.
1920 | // Read out fully processed segment.
1921 | for (i = self->windShift; i < self->blockLen + self->windShift; i++) {
1922 | fout[i - self->windShift] = self->syntBuf[i];
1923 | }
1924 | // Update synthesis buffer.
1925 | UpdateBuffer(NULL, self->blockLen, self->anaLen, self->syntBuf);
1926 |
1927 | for (i = 0; i < self->blockLen; ++i)
1928 | outFrame[0][i] =
1929 | SPL_SAT(32767, fout[i], (-32768));
1930 |
1931 | // For time-domain gain of HB.
1932 | if (flagHB == 1) {
1933 | for (i = 0; i < num_high_bands; ++i) {
1934 | for (j = 0; j < self->blockLen; ++j) {
1935 | outFrameHB[i][j] = SPL_SAT(32767,
1936 | self->dataBufHB[i][j],
1937 | (-32768));
1938 | }
1939 | }
1940 | }
1941 |
1942 | return;
1943 | }
1944 |
1945 | FFT(self, winData, self->anaLen, self->magnLen, real, imag, magn);
1946 |
1947 | if (self->blockInd < END_STARTUP_SHORT) {
1948 | for (i = 0; i < self->magnLen; i++) {
1949 | self->initMagnEst[i] += magn[i];
1950 | }
1951 | }
1952 |
1953 | ComputeDdBasedWienerFilter(self, magn, theFilter);
1954 |
1955 | for (i = 0; i < self->magnLen; i++) {
1956 | // Flooring bottom.
1957 | if (theFilter[i] < self->denoiseBound) {
1958 | theFilter[i] = self->denoiseBound;
1959 | }
1960 | // Flooring top.
1961 | if (theFilter[i] > 1.f) {
1962 | theFilter[i] = 1.f;
1963 | }
1964 | if (self->blockInd < END_STARTUP_SHORT) {
1965 | theFilterTmp[i] =
1966 | (self->initMagnEst[i] - self->overdrive * self->parametricNoise[i]);
1967 | theFilterTmp[i] /= (self->initMagnEst[i] + 0.0001f);
1968 | // Flooring bottom.
1969 | if (theFilterTmp[i] < self->denoiseBound) {
1970 | theFilterTmp[i] = self->denoiseBound;
1971 | }
1972 | // Flooring top.
1973 | if (theFilterTmp[i] > 1.f) {
1974 | theFilterTmp[i] = 1.f;
1975 | }
1976 | // Weight the two suppression filters.
1977 | theFilter[i] *= (self->blockInd);
1978 | theFilterTmp[i] *= (END_STARTUP_SHORT - self->blockInd);
1979 | theFilter[i] += theFilterTmp[i];
1980 | theFilter[i] /= (END_STARTUP_SHORT);
1981 | }
1982 |
1983 | self->smooth[i] = theFilter[i];
1984 | real[i] *= self->smooth[i];
1985 | imag[i] *= self->smooth[i];
1986 | }
1987 | // Keep track of |magn| spectrum for next frame.
1988 | memcpy(self->magnPrevProcess, magn, sizeof(*magn) * self->magnLen);
1989 | memcpy(self->noisePrev, self->noise, sizeof(self->noise[0]) * self->magnLen);
1990 | // Back to time domain.
1991 | IFFT(self, real, imag, self->magnLen, self->anaLen, winData);
1992 |
1993 | // Scale factor: only do it after END_STARTUP_LONG time.
1994 | factor = 1.f;
1995 | if (self->gainmap == 1 && self->blockInd > END_STARTUP_LONG) {
1996 | factor1 = 1.f;
1997 | factor2 = 1.f;
1998 | energy2 = Energy(winData, self->anaLen);
1999 | gain = sqrtf(energy2 / (energy1 + 1.f));
2000 |
2001 | // Scaling for new version.
2002 | if (gain > B_LIM) {
2003 | factor1 = 1.f + 1.3f * (gain - B_LIM);
2004 | if (gain * factor1 > 1.f) {
2005 | factor1 = 1.f / gain;
2006 | }
2007 | }
2008 | if (gain < B_LIM) {
2009 | // Don't reduce scale too much for pause regions:
2010 | // attenuation here should be controlled by flooring.
2011 | if (gain <= self->denoiseBound) {
2012 | gain = self->denoiseBound;
2013 | }
2014 | factor2 = 1.f - 0.3f * (B_LIM - gain);
2015 | }
2016 | // Combine both scales with speech/noise prob:
2017 | // note prior (priorSpeechProb) is not frequency dependent.
2018 | factor = self->priorSpeechProb * factor1 +
2019 | (1.f - self->priorSpeechProb) * factor2;
2020 | } // Out of self->gainmap == 1.
2021 |
2022 | Windowing(self->window, winData, self->anaLen, winData);
2023 |
2024 | // Synthesis.
2025 | for (i = 0; i < self->anaLen; i++) {
2026 | self->syntBuf[i] += factor * winData[i];
2027 | }
2028 | // Read out fully processed segment.
2029 | for (i = self->windShift; i < self->blockLen + self->windShift; i++) {
2030 | fout[i - self->windShift] = self->syntBuf[i];
2031 | }
2032 | // Update synthesis buffer.
2033 | UpdateBuffer(NULL, self->blockLen, self->anaLen, self->syntBuf);
2034 |
2035 | for (i = 0; i < self->blockLen; ++i)
2036 | outFrame[0][i] =
2037 | SPL_SAT(32767, fout[i], (-32768));
2038 |
2039 | // For time-domain gain of HB.
2040 | if (flagHB == 1) {
2041 | // Average speech prob from low band.
2042 | // Average over second half (i.e., 4->8kHz) of frequencies spectrum.
2043 | avgProbSpeechHB = 0.0;
2044 | for (i = self->magnLen - deltaBweHB - 1; i < self->magnLen - 1; i++) {
2045 | avgProbSpeechHB += self->speechProb[i];
2046 | }
2047 | avgProbSpeechHB = avgProbSpeechHB / ((float) deltaBweHB);
2048 | // If the speech was suppressed by a component between Analyze and
2049 | // Process, for example the AEC, then it should not be considered speech
2050 | // for high band suppression purposes.
2051 | sumMagnAnalyze = 0;
2052 | sumMagnProcess = 0;
2053 | for (i = 0; i < self->magnLen; ++i) {
2054 | sumMagnAnalyze += self->magnPrevAnalyze[i];
2055 | sumMagnProcess += self->magnPrevProcess[i];
2056 | }
2057 | avgProbSpeechHB *= sumMagnProcess / sumMagnAnalyze;
2058 | // Average filter gain from low band.
2059 | // Average over second half (i.e., 4->8kHz) of frequencies spectrum.
2060 | avgFilterGainHB = 0.0;
2061 | for (i = self->magnLen - deltaGainHB - 1; i < self->magnLen - 1; i++) {
2062 | avgFilterGainHB += self->smooth[i];
2063 | }
2064 | avgFilterGainHB = avgFilterGainHB / ((float) (deltaGainHB));
2065 | avgProbSpeechHBTmp = 2.f * avgProbSpeechHB - 1.f;
2066 | // Gain based on speech probability.
2067 | gainModHB = 0.5f * (1.f + tanhf(gainMapParHB * avgProbSpeechHBTmp));
2068 | // Combine gain with low band gain.
2069 | float gainTimeDomainHB = 0.5f * gainModHB + 0.5f * avgFilterGainHB;
2070 | if (avgProbSpeechHB >= 0.5f) {
2071 | gainTimeDomainHB = 0.25f * gainModHB + 0.75f * avgFilterGainHB;
2072 | }
2073 | gainTimeDomainHB = gainTimeDomainHB * decayBweHB;
2074 | // Make sure gain is within flooring range.
2075 | // Flooring bottom.
2076 | if (gainTimeDomainHB < self->denoiseBound) {
2077 | gainTimeDomainHB = self->denoiseBound;
2078 | }
2079 | // Flooring top.
2080 | if (gainTimeDomainHB > 1.f) {
2081 | gainTimeDomainHB = 1.f;
2082 | }
2083 | // Apply gain.
2084 | for (i = 0; i < num_high_bands; ++i) {
2085 | for (j = 0; j < self->blockLen; j++) {
2086 | outFrameHB[i][j] =
2087 | SPL_SAT(32767,
2088 | gainTimeDomainHB * self->dataBufHB[i][j],
2089 | (-32768));
2090 | }
2091 | }
2092 | } // End of H band gain computation.
2093 | }
2094 |
2095 | NsHandle *WebRtcNs_Create() {
2096 | NoiseSuppressionC *self = (NoiseSuppressionC *) malloc(sizeof(NoiseSuppressionC));
2097 | if (self != NULL) {
2098 | self->initFlag = 0;
2099 | }
2100 | return (NsHandle *) self;
2101 | }
2102 |
2103 | void WebRtcNs_Free(NsHandle *NS_inst) {
2104 | free(NS_inst);
2105 | }
2106 |
2107 | int WebRtcNs_Init(NsHandle *NS_inst, uint32_t fs) {
2108 | return WebRtcNs_InitCore((NoiseSuppressionC *) NS_inst, fs);
2109 | }
2110 |
2111 | int WebRtcNs_set_policy(NsHandle *NS_inst, int mode) {
2112 | return WebRtcNs_set_policy_core((NoiseSuppressionC *) NS_inst, mode);
2113 | }
2114 |
2115 | void WebRtcNs_Analyze(NsHandle *NS_inst, const int16_t *spframe) {
2116 | WebRtcNs_AnalyzeCore((NoiseSuppressionC *) NS_inst, spframe);
2117 | }
2118 |
2119 | void WebRtcNs_Process(NsHandle *NS_inst,
2120 | const int16_t *const *spframe,
2121 | size_t num_bands,
2122 | int16_t *const *outframe) {
2123 | WebRtcNs_ProcessCore((NoiseSuppressionC *) NS_inst, spframe, num_bands,
2124 | outframe);
2125 | }
2126 |
2127 | float WebRtcNs_prior_speech_probability(NsHandle *handle) {
2128 | NoiseSuppressionC *self = (NoiseSuppressionC *) handle;
2129 | if (handle == NULL) {
2130 | return -1;
2131 | }
2132 | if (self->initFlag == 0) {
2133 | return -1;
2134 | }
2135 | return self->priorSpeechProb;
2136 | }
2137 |
2138 | const float *WebRtcNs_noise_estimate(const NsHandle *handle) {
2139 | const NoiseSuppressionC *self = (const NoiseSuppressionC *) handle;
2140 | if (handle == NULL || self->initFlag == 0) {
2141 | return NULL;
2142 | }
2143 | return self->noise;
2144 | }
2145 |
2146 | size_t WebRtcNs_num_freq() {
2147 | return HALF_ANAL_BLOCKL;
2148 | }
2149 |
--------------------------------------------------------------------------------