Merge branch 'master' into randr

Conflicts:
	ChangeLog
This commit is contained in:
Sergii Stoian 2020-02-23 03:04:19 +02:00
commit c0c5cad292
24 changed files with 1054 additions and 88 deletions

2
.gitignore vendored
View file

@ -3,6 +3,7 @@ obj
*.sum
*.bundle
*.service
autom4te.cache
config.log
config.status
config.cache
@ -15,6 +16,7 @@ Source/config.h
Source/Info-gnustep.plist
Tests/gui/*/GNUmakefile
Tools/speech/GSSpeechServer.app
Tools/speech_recognizer/GSSpeechRecognitionServer.app
*~
# Created by https://www.gitignore.io/api/xcode

View file

@ -2,6 +2,14 @@
* Source/NSMenu.m (windowDidChangeScreen:): join two if statements.
2020-02-20 Sergii Stoian <stoyan255@gmail.com>
* Source/NSMenu.m (_setGeometry): take into account main screen
origin when calculating horizontal menu postion.
* Source/NSApplication.m (_appIconInit): take into account main screen
origin when placing application icon.
2020-02-13 Sergii Stoian <stoyan255@gmail.com>
* Source/NSWindow.m (setFrame:display:): use _screeForFrame: here

View file

@ -19,7 +19,7 @@
#undef HAVE_FLITE_FLITE_H
/* Define to 1 if you have the pocketsphinx.h header file */
#undef HAVE_POCKETSPHINX_H
#undef HAVE_POCKETSPHINX_POCKETSPHINX_EXPORT_H
/* Define to 1 if you have the `floorf' function. */
#undef HAVE_FLOORF

View file

@ -26,6 +26,7 @@
#define _NSSpeechRecognizer_h_GNUSTEP_GUI_INCLUDE
#import <Foundation/NSObject.h>
#import <AppKit/AppKitDefines.h>
#if OS_API_VERSION(MAC_OS_X_VERSION_10_0, GS_API_LATEST)
@ -33,10 +34,55 @@
extern "C" {
#endif
@interface NSSpeechRecognizer : NSObject
@protocol NSSpeechRecognizerDelegate;
@class NSArray, NSString, NSUUID;
@interface NSSpeechRecognizer : NSObject
{
id<NSSpeechRecognizerDelegate> _delegate;
NSArray *_commands;
NSString *_displayCommandsTitle;
NSUUID *_uuid;
BOOL _blocksOtherRecognizers;
BOOL _listensInForegroundOnly;
BOOL _appInForeground; // private
BOOL _isListening;
}
// Initialize
- (instancetype) init;
- (id<NSSpeechRecognizerDelegate>) delegate;
- (void) setDelegate: (id<NSSpeechRecognizerDelegate>) delegate;
// Configuring...
- (NSArray *) commands;
- (void) setCommands: (NSArray *)commands;
- (NSString *) displayCommandsTitle;
- (void) setDisplayCommandsTitle: (NSString *)displayCommandsTitle;
- (BOOL) listensInForegroundOnly;
- (void) setListensInForegroundOnly: (BOOL)listensInForegroundOnly;
- (BOOL) blocksOtherRecognizers;
- (void) setBlocksOtherRecognizers: (BOOL)blocksOtherRecognizers;
// Listening
- (void) startListening;
- (void) stopListening;
@end
// Protocol
@protocol NSSpeechRecognizerDelegate
- (void) speechRecognizer: (NSSpeechRecognizer *)sender
didRecognizeCommand: (NSString *)command;
@end
APPKIT_EXPORT NSString *GSSpeechRecognizerDidRecognizeWordNotification;
#if defined(__cplusplus)
}
#endif

View file

@ -36,7 +36,7 @@ typedef enum
NSSpeechImmediateBoundary = 0,
NSSpeechWordBoundary,
NSSpeechSentenceBoundary
}
}
NSSpeechBoundary;
// forward declarations...
@ -184,3 +184,4 @@ extern NSString *NSSpeechDictionaryEntryPhonemes;
@end
#endif // _GNUstep_H_NSSpeechSynthesizer

View file

@ -30,8 +30,6 @@ MISSING HEADERS
> NSLayoutGuide.h
> NSMediaLibraryBrowserController.h
> NSMenuToolbarItem.h
> NSNibControlConnector.h
> NSNibOutletConnector.h
> NSOpenGLLayer.h
> NSPageController.h
> NSPathCell.h
@ -47,7 +45,6 @@ MISSING HEADERS
> NSScrubberLayout.h
> NSSharingServicePickerToolbarItem.h
> NSSliderAccessory.h
> NSSpeechRecognizer.h
> NSSplitViewController.h
> NSSplitViewItem.h
> NSStackView.h
@ -87,6 +84,7 @@ Completed
> NSDataAsset.h
> NSTouch.h
> NSTouchBar.h
> NSSpeechRecognizer.h
Mac Specific
---
@ -106,7 +104,6 @@ Mac Specific
> NSPanGestureRecognizer.h
> NSPressGestureRecognizer.h
> NSRotationGestureRecognizer.h
> NSSpeechRecognizer.h
> NSApplicationScripting.h
> NSDocumentScripting.h
> NSTextStorageScripting.h

View file

@ -118,7 +118,6 @@ NSPressGestureRecognizer.m \
NSRotationGestureRecognizer.m \
NSSharingServicePickerTouchBarItem.m \
NSSliderTouchBarItem.m \
NSSpeechRecognizer.m \
NSStepperTouchBarItem.m \
NSTouch.m \
NSTouchBar.m \
@ -149,7 +148,6 @@ NSPressGestureRecognizer.m \
NSRotationGestureRecognizer.m \
NSSharingServicePickerTouchBarItem.m \
NSSliderTouchBarItem.m \
NSSpeechRecognizer.m \
NSStepperTouchBarItem.m \
NSMagnificationGestureRecognizer.m \
NSMatrix.m \

View file

@ -3896,6 +3896,7 @@ struct _DelegateWrapper
iconContentRect = GSGetIconFrame(_app_icon_window);
iconFrame = [_app_icon_window frameRectForContentRect: iconContentRect];
iconFrame.origin = [[NSScreen mainScreen] frame].origin;
iconViewFrame = NSMakeRect(0, 0,
iconContentRect.size.width, iconContentRect.size.height);
[_app_icon_window setFrame: iconFrame display: YES];

View file

@ -470,8 +470,10 @@ static BOOL menuBarVisible = YES;
if (_menu.horizontal == YES)
{
origin = NSMakePoint (0, [[NSScreen mainScreen] frame].size.height
- [_aWindow frame].size.height);
NSRect screenFrame = [[NSScreen mainScreen] frame];
origin = NSMakePoint (0, screenFrame.size.height
- [_aWindow frame].size.height);
origin.y += screenFrame.origin.y;
[_aWindow setFrameOrigin: origin];
[_bWindow setFrameOrigin: origin];
}

View file

@ -23,8 +23,313 @@
*/
#import <AppKit/NSSpeechRecognizer.h>
#import <AppKit/NSApplication.h>
#import <Foundation/NSDistantObject.h>
#import <Foundation/NSString.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSThread.h>
#import <Foundation/NSError.h>
#import <Foundation/NSConnection.h>
#import <Foundation/NSDistributedNotificationCenter.h>
#import <Foundation/NSDebug.h>
#import <Foundation/NSUUID.h>
#import "GSFastEnumeration.h"
#import "AppKit/NSWorkspace.h"
#import "AppKit/NSWindow.h"
@implementation NSSpeechRecognizer
id _speechRecognitionServer = nil;
BOOL _serverLaunchTested = NO;
#define SPEECH_RECOGNITION_SERVER @"GSSpeechRecognitionServer"
@interface NSObject (SpeechRecognitionServerPrivate)
- (void) addToBlockingRecognizers: (NSString *)s;
- (void) removeFromBlockingRecognizers: (NSString *)s;
- (BOOL) isBlocking: (NSString *)s;
- (void) addClient;
@end
@implementation NSSpeechRecognizer
+ (void) initialize
{
if (self == [NSSpeechRecognizer class])
{
// Test for an existant server...
_speechRecognitionServer =
[NSConnection rootProxyForConnectionWithRegisteredName: SPEECH_RECOGNITION_SERVER
host: nil];
// if none exists, start one. We will connect with it in init.
if (nil == _speechRecognitionServer)
{
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
[ws launchApplication: SPEECH_RECOGNITION_SERVER
showIcon: NO
autolaunch: NO];
}
}
}
- (void) _restartServer
{
if (nil == _speechRecognitionServer && !_serverLaunchTested)
{
unsigned int i = 0;
// Wait for up to five seconds for the server to launch, then give up.
for (i = 0 ; i < 50 ; i++)
{
_speechRecognitionServer = [NSConnection
rootProxyForConnectionWithRegisteredName: SPEECH_RECOGNITION_SERVER
host: nil];
RETAIN(_speechRecognitionServer);
if (nil != _speechRecognitionServer)
{
NSDebugLog(@"Server found!!!");
break;
}
else
{
NS_DURING
{
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
[ws launchApplication: SPEECH_RECOGNITION_SERVER
showIcon: NO
autolaunch: NO];
}
NS_HANDLER
{
}
NS_ENDHANDLER;
}
[NSThread sleepForTimeInterval: 0.1];
}
// Set a flag so we don't bother waiting for the speech recognition server to
// launch the next time if it didn't work this time.
_serverLaunchTested = YES;
}
if (_speechRecognitionServer == nil)
{
NSLog(@"Cannot restart speech recognition server.");
}
}
- (void) processNotification: (NSNotification *)note
{
NSString *word = (NSString *)[note object];
NSDebugLog(@"Notified");
if (_listensInForegroundOnly)
{
if (_appInForeground == NO)
{
NSDebugLog(@"Only in foreground..");
return;
}
}
if (_blocksOtherRecognizers)
{
NS_DURING
{
/*
if ([_speechRecognitionServer isBlocking: [_uuid UUIDString]] == NO)
{
// If we are not a blocking recognizer, then we are blocked...
NSDebugLog(@"Blocked...");
return;
}
*/
}
NS_HANDLER
{
NSLog(@"%@", localException);
[self _restartServer];
}
NS_ENDHANDLER;
}
word = [word lowercaseString];
FOR_IN(NSString*, obj, _commands)
{
if ([[obj lowercaseString] isEqualToString: word])
{
[_delegate speechRecognizer: self
didRecognizeCommand: word];
}
}
END_FOR_IN(_commands);
}
- (void) processAppStatusNotification: (NSNotification *)note
{
NSString *name = [note name];
if ([name isEqualToString: NSApplicationDidBecomeActiveNotification] ||
[name isEqualToString: NSApplicationDidFinishLaunchingNotification] ||
[name isEqualToString: NSWindowDidBecomeKeyNotification])
{
_appInForeground = YES;
}
else
{
_appInForeground = NO;
}
}
// Initialize
- (instancetype) init
{
self = [super init];
if (self != nil)
{
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(processAppStatusNotification:)
name: NSApplicationDidFinishLaunchingNotification
object: nil];
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(processAppStatusNotification:)
name: NSWindowDidBecomeKeyNotification
object: nil];
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(processAppStatusNotification:)
name: NSApplicationDidBecomeActiveNotification
object: nil];
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(processAppStatusNotification:)
name: NSApplicationDidResignActiveNotification
object: nil];
_delegate = nil;
_blocksOtherRecognizers = NO;
_listensInForegroundOnly = YES;
_appInForeground = YES;
_uuid = [NSUUID UUID];
[self _restartServer];
}
NS_DURING
{
[_speechRecognitionServer addClient]; // do this to update the client count;
}
NS_HANDLER
{
NSLog(@"%@", localException);
[self _restartServer];
}
NS_ENDHANDLER;
return self;
}
- (void) dealloc
{
[[NSDistributedNotificationCenter defaultCenter] removeObserver: self];
[[NSNotificationCenter defaultCenter] removeObserver: self];
_delegate = nil;
[super dealloc];
}
// Delegate
- (id<NSSpeechRecognizerDelegate>) delegate
{
return _delegate;
}
- (void) setDelegate: (id<NSSpeechRecognizerDelegate>)delegate
{
_delegate = delegate;
}
// Configuring...
- (NSArray *) commands
{
return _commands;
}
- (void) setCommands: (NSArray *)commands
{
ASSIGNCOPY(_commands, commands);
}
- (NSString *) displayCommandsTitle
{
return _displayCommandsTitle;
}
- (void) setDisplayCommandsTitle: (NSString *)displayCommandsTitle
{
ASSIGNCOPY(_displayCommandsTitle, displayCommandsTitle);
}
- (BOOL) listensInForegroundOnly
{
return _listensInForegroundOnly;
}
- (void) setListensInForegroundOnly: (BOOL)listensInForegroundOnly
{
_listensInForegroundOnly = listensInForegroundOnly;
}
- (BOOL) blocksOtherRecognizers
{
return _blocksOtherRecognizers;
}
- (void) setBlocksOtherRecognizers: (BOOL)blocksOtherRecognizers
{
NS_DURING
{
if (blocksOtherRecognizers == YES)
{
[_speechRecognitionServer addToBlockingRecognizers: [_uuid UUIDString]];
}
else
{
[_speechRecognitionServer removeFromBlockingRecognizers: [_uuid UUIDString]];
}
_blocksOtherRecognizers = blocksOtherRecognizers;
}
NS_HANDLER
{
NSLog(@"%@", localException);
[self _restartServer];
}
NS_ENDHANDLER;
}
// Listening
- (void) startListening
{
// Start listening to the notification being sent by the server....
[[NSDistributedNotificationCenter defaultCenter]
addObserver: self
selector: @selector(processNotification:)
name: GSSpeechRecognizerDidRecognizeWordNotification
object: nil];
}
- (void) stopListening
{
// Remove the observer for the notification....
[[NSDistributedNotificationCenter defaultCenter]
removeObserver: self
name: GSSpeechRecognizerDidRecognizeWordNotification
object: nil];
}
@end

View file

@ -102,58 +102,60 @@ static Class NSSpeechSynthesizerClass;
- (NSSpeechSynthesizer*)newSynthesizer;
@end
@implementation NSSpeechSynthesizer
@implementation NSSpeechSynthesizer
- (id) initWithVoice: (NSString *)voice
{
return self;
}
+ (void)initialize
{
NSSpeechSynthesizerClass = [NSSpeechSynthesizer class];
server = [[NSConnection rootProxyForConnectionWithRegisteredName: @"GSSpeechServer"
host: nil] retain];
if (nil == server)
{
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
[ws launchApplication: @"GSSpeechServer"
showIcon: NO
autolaunch: NO];
}
NSSpeechSynthesizerClass = [NSSpeechSynthesizer class];
server = [[NSConnection rootProxyForConnectionWithRegisteredName: @"GSSpeechServer"
host: nil] retain];
if (nil == server)
{
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
[ws launchApplication: @"GSSpeechServer"
showIcon: NO
autolaunch: NO];
}
}
+ (BOOL)isAnyApplicationSpeaking
{
return [server isSpeaking];
return [server isSpeaking];
}
// Never really allocate one of these.
+ (id)allocWithZone: (NSZone*)aZone
{
if (self == NSSpeechSynthesizerClass)
{
if (nil == server && !serverLaunchTested)
{
unsigned int i=0;
// Wait for up to five seconds for the server to launch, then give up.
for (i=0 ; i<50 ; i++)
{
server =
[[NSConnection rootProxyForConnectionWithRegisteredName:
@"GSSpeechServer"
host: nil]
retain];
if (nil != server)
{
break;
}
[NSThread sleepForTimeInterval: 0.1];
}
// Set a flag so we don't bother waiting for the speech server to
// launch the next time if it didn't work this time.
serverLaunchTested = YES;
}
// If there is no server, this will return nil
return [server newSynthesizer];
}
return [super allocWithZone: aZone];
if (self == NSSpeechSynthesizerClass)
{
if (nil == server && !serverLaunchTested)
{
unsigned int i = 0;
// Wait for up to five seconds for the server to launch, then give up.
for (i=0 ; i < 50 ; i++)
{
server = [NSConnection rootProxyForConnectionWithRegisteredName: @"GSSpeechServer"
host: nil];
RETAIN(server);
if (nil != server)
{
break;
}
[NSThread sleepForTimeInterval: 0.1];
}
// Set a flag so we don't bother waiting for the speech server to
// launch the next time if it didn't work this time.
serverLaunchTested = YES;
}
// If there is no server, this will return nil
return [server newSynthesizer];
}
return [super allocWithZone: aZone];
}
// configuring speech synthesis

View file

@ -812,6 +812,10 @@ const NSAppearanceName NSAppearanceNameAccessibilityHighContrastVibrantDark =
@"NSAppearanceNameAccessibilityHighContrastVibrantDark";
const NSAppearanceName NSAppearanceNameLightContent = @"NSAppearanceNameLightContent";
// Speech recognition...
const NSString *GSSpeechRecognizerDidRecognizeWordNotification = @"GSSpeechRecognizerDidRecognizeWordNotification";
extern void __objc_gui_force_linking (void);
void

View file

@ -28,7 +28,7 @@ include ../config.make
include ../Version
SUBPROJECTS = $(BUILD_SPEECH) $(BUILD_SOUND) $(BUILD_SPEECH_RECOGNITION)
SUBPROJECTS = $(BUILD_SPEECH) $(BUILD_SOUND) $(BUILD_SPEECH_RECOGNIZER)
TOOL_NAME = make_services set_show_service gopen gclose gcloseall
SERVICE_NAME = GSspell

View file

@ -8,65 +8,80 @@ static GSSpeechServer *sharedInstance;
@implementation GSSpeechServer
+ (void)initialize
{
sharedInstance = [self new];
sharedInstance = [self new];
}
+ (void)start
{
NSConnection *connection = [NSConnection defaultConnection];
[connection setRootObject: sharedInstance];
if (NO == [connection registerName: @"GSSpeechServer"])
{
return;
}
[[NSRunLoop currentRunLoop] run];
NSConnection *connection = [NSConnection defaultConnection];
[connection setRootObject: sharedInstance];
if (NO == [connection registerName: @"GSSpeechServer"])
{
return;
}
[[NSRunLoop currentRunLoop] run];
}
+ (id)sharedServer
{
return sharedInstance;
return sharedInstance;
}
- (id)init
{
if (nil == (self = [super init])) { return nil; }
engine = [GSSpeechEngine defaultSpeechEngine];
if (nil == engine)
{
[self release];
return nil;
}
return self;
if (nil == (self = [super init]))
{
return nil;
}
engine = [GSSpeechEngine defaultSpeechEngine];
if (nil == engine)
{
[self release];
return nil;
}
return self;
}
- (id)newSynthesizer
{
return [[GSSpeechSynthesizer new] autorelease];
return [[GSSpeechSynthesizer new] autorelease];
}
- (BOOL)startSpeakingString: (NSString*)aString notifyWhenDone: (id)client
{
[engine stopSpeaking];
[engine startSpeaking: aString notifyWhenDone: client];
return YES;
[engine stopSpeaking];
[engine startSpeaking: aString notifyWhenDone: client];
return YES;
}
- (void)stopSpeaking
{
[engine stopSpeaking];
[engine stopSpeaking];
}
- (BOOL)isSpeaking
{
return [engine isSpeaking];
return [engine isSpeaking];
}
- (NSArray*)voices
{
return [engine voices];
return [engine voices];
}
- (oneway void)setVoice: (NSString*)aVoice
{
[engine setVoice: aVoice];
[engine setVoice: aVoice];
}
- (NSString*)voice
{
return [engine voice];
return [engine voice];
}
- (NSString*)defaultVoice
{
return [engine defaultVoice];
return [engine defaultVoice];
}
@end

View file

@ -0,0 +1,26 @@
include $(GNUSTEP_MAKEFILES)/common.make
include ../../config.make
VERSION = 0.1
# This is an app not a tool because, eventually, it will present the user
# interface for the GUI part of the speech engine.
APP_NAME = GSSpeechRecognitionServer
GSSpeechRecognitionServer_LANGUAGES = English
GSSpeechRecognitionServer_OBJC_FILES = \
GSSpeechRecognitionEngine.m \
GSSpeechRecognitionServer.m \
main.m
# Add includes and link dirs....
GSSpeechRecognitionServer_OBJC_FILES += $(RECOGNIZER_ENGINE_CLASS)
GSSpeechRecognitionServer_INCLUDE_DIRS += $(RECOGNIZER_BASE_CFLAGS) \
-I../../Headers \
-I../../Headers/Additions
GSSpeechRecognitionServer_LIB_DIRS += -L../../Source/$(GNUSTEP_OBJ_DIR) \
-L/usr/local/lib -lgnustep-gui \
$(RECOGNIZER_BASE_LIBS)
include $(GNUSTEP_MAKEFILES)/application.make

View file

@ -0,0 +1,49 @@
/* Interface of class GSSpeechRecognitionEngine
Copyright (C) 2019 Free Software Foundation, Inc.
By: Gregory John Casamento
Date: Fri Dec 6 04:55:59 EST 2019
This file is part of the GNUstep Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import <Foundation/Foundation.h>
#import <AppKit/NSSpeechRecognizer.h>
/**
* GSSpeechRecognitionEngine is an abstract speech server. One concrete subclass should
* be implemented for each speech recognition engine. Currently, only one may be compiled
* into the speech recognition server at any given time. This limitation may be removed
* in future if pluggable speech engines are considered beneficial.
*/
@interface GSSpeechRecognitionEngine : NSObject
- (void) start;
- (void) stop;
@end
@interface NSObject (GSSpeechRecognitionEngineDelegate)
@end
@interface GSSpeechRecognitionEngine (Default)
/**
* Returns a new instance of the default speech engine.
*/
+ (GSSpeechRecognitionEngine*)defaultSpeechRecognitionEngine;
@end

View file

@ -0,0 +1,49 @@
/* Implementation of class GSSpeechRecognitionEngine
Copyright (C) 2019 Free Software Foundation, Inc.
By: Gregory John Casamento
Date: Fri Dec 6 04:55:59 EST 2019
This file is part of the GNUstep Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import "GSSpeechRecognitionEngine.h"
/**
* Dummy implementation of a speech engine. Doesn't do anything.
*/
@implementation GSSpeechRecognitionEngine
+ (GSSpeechRecognitionEngine*) defaultSpeechEngine
{
return AUTORELEASE([[self alloc] init]);
}
- (void) recognize
{
}
- (void) start
{
}
- (void) stop
{
}
@end

View file

@ -0,0 +1,53 @@
/* Interface of class GSSpeechRecognitionServer
Copyright (C) 2019 Free Software Foundation, Inc.
By: Gregory John Casamento
Date: Fri Dec 6 04:55:59 EST 2019
This file is part of the GNUstep Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import <Foundation/Foundation.h>
#import <AppKit/NSSpeechRecognizer.h>
@class GSSpeechRecognitionEngine;
/**
* GSSpeechRecognitionServer handles all of the engine-agnostic operations. Currently,
* there aren't any, but when the on-screen text interface is added it should
* go in here.
*/
@interface GSSpeechRecognitionServer : NSObject
{
GSSpeechRecognitionEngine *_engine;
NSMutableArray *_blocking;
}
/**
* Returns a shared instance of the speech server.
*/
+ (id)sharedServer;
// Add or remove from blocking list...
- (void) addToBlockingRecognizers: (NSString *)s;
- (void) removeFromBlockingRecognizers: (NSString *)s;
- (BOOL) isBlocking: (NSString *)s;
// Connection...
- (void) addClient;
@end

View file

@ -0,0 +1,146 @@
/* Implementation of class GSSpeechRecognitionServer
Copyright (C) 2019 Free Software Foundation, Inc.
By: Gregory John Casamento
Date: Fri Dec 6 04:55:59 EST 2019
This file is part of the GNUstep Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import "GSSpeechRecognitionServer.h"
#import "GSSpeechRecognitionEngine.h"
#import <Foundation/Foundation.h>
static GSSpeechRecognitionServer *_sharedInstance;
static int _clients = 0;
@implementation GSSpeechRecognitionServer
/**
* Monitor connection...
*/
+ (void)connectionDied: (NSNotification*)aNotification
{
NSArray *objs = [[aNotification object] localObjects];
NSEnumerator *en = [objs objectEnumerator];
id o = nil;
if(_clients > 0)
{
_clients--;
}
if(_clients == 0)
{
NSDebugLog(@"Client count is zero, exiting");
exit(0);
}
NSDebugLog(@"NSSpeechRecognizer server connection count = %d after disconnection", _clients);
while((o = [en nextObject]) != nil)
{
if ([o isKindOfClass: self])
{
RELEASE(o);
}
}
}
+ (void)initialize
{
_sharedInstance = [[self alloc] init];
_clients = 0;
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(connectionDied:)
name: NSConnectionDidDieNotification
object: nil];
}
+ (void)start
{
NSConnection *connection = [NSConnection defaultConnection];
[connection setRootObject: _sharedInstance];
RETAIN(connection);
if (NO == [connection registerName: @"GSSpeechRecognitionServer"])
{
NSLog(@"Could not register name, make sure another server is not running.");
return;
}
[[NSRunLoop currentRunLoop] run];
}
+ (id)sharedServer
{
NSDebugLog(@"NSSpeechRecognizer server connection count = %d after connection", _clients);
return _sharedInstance;
}
- (void) addClient
{
_clients++;
}
- (id)init
{
if (nil == (self = [super init]))
{
return nil;
}
_engine = [GSSpeechRecognitionEngine defaultSpeechRecognitionEngine];
if (nil == _engine)
{
[self release];
return nil;
}
else
{
NSDebugLog(@"Got engine starting... %@", _engine);
[_engine start];
}
_blocking = [[NSMutableArray alloc] initWithCapacity: 10];
return self;
}
- (void) dealloc
{
[_engine stop];
RELEASE(_engine);
RELEASE(_blocking);
[super dealloc];
}
- (void) addToBlockingRecognizers: (NSString *)s
{
[_blocking addObject: s];
}
- (void) removeFromBlockingRecognizers: (NSString *)s
{
[_blocking removeObject: s];
}
- (BOOL) isBlocking: (NSString *)s
{
return [[_blocking lastObject] isEqualToString: s];
}
@end

View file

@ -0,0 +1,233 @@
/* Implementation of class PocketsphinxSpeechRecognitionEngine
Copyright (C) 2019 Free Software Foundation, Inc.
By: Gregory John Casamento
Date: Fri Dec 6 04:55:59 EST 2019
This file is part of the GNUstep Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import "GSSpeechRecognitionEngine.h"
#import <Foundation/NSDistributedNotificationCenter.h>
#include <sphinxbase/err.h>
#include <sphinxbase/ad.h>
#include <pocketsphinx/pocketsphinx.h>
/**
* Implementation of a speech engine using pocketsphinx. This should be the default
* for resource-constrained platforms.
*/
#define MODELDIR "/share/pocketsphinx/model"
static const arg_t cont_args_def[] = {
POCKETSPHINX_OPTIONS,
/* Argument file. */
{"-argfile",
ARG_STRING,
NULL,
"Argument file giving extra arguments."},
{"-adcdev",
ARG_STRING,
NULL,
"Name of audio device to use for input."},
{"-infile",
ARG_STRING,
NULL,
"Audio file to transcribe."},
{"-inmic",
ARG_BOOLEAN,
"yes",
"Transcribe audio from microphone."},
{"-time",
ARG_BOOLEAN,
"no",
"Print word times in file transcription."},
CMDLN_EMPTY_OPTION
};
@interface PocketsphinxSpeechRecognitionEngine : GSSpeechRecognitionEngine
{
ps_decoder_t *ps;
cmd_ln_t *config;
FILE *fh;
char const *uttid;
int16 buf[512];
int rv;
int32 score;
NSThread *_listeningThread;
id<NSSpeechRecognizerDelegate> _delegate;
}
@end
@implementation PocketsphinxSpeechRecognitionEngine
- (id)init
{
if ((self = [super init]) != nil)
{
char *arg[3];
arg[0] = "";
arg[1] = "-inmic";
arg[2] = "yes";
config = cmd_ln_parse_r(NULL, cont_args_def, 3, arg, TRUE);
// turn off pocketsphinx output
err_set_logfp(NULL);
err_set_debug_level(0);
ps_default_search_args(config);
ps = ps_init(config);
if (ps == NULL)
{
cmd_ln_free_r(config);
NSLog(@"Could not start server");
return nil;
}
_listeningThread = nil;
}
return self;
}
- (void) _recognizedWord: (NSString *)word
{
[[NSDistributedNotificationCenter defaultCenter]
postNotificationName: GSSpeechRecognizerDidRecognizeWordNotification
object: word
userInfo: nil];
}
/*
* NOTE: This code is derived from continuous.c under pocketsphinx
* which is MIT licensed
* Main utterance processing loop:
* while (YES) {
* start utterance and wait for speech to process
* decoding till end-of-utterance silence will be detected
* print utterance result;
* }
*/
- (void) recognize
{
ad_rec_t *ad;
int16 adbuf[2048];
BOOL utt_started, in_speech;
int32 k;
char const *hyp;
NSDebugLog(@"** Starting speech recognition loop");
if ((ad = ad_open_dev(cmd_ln_str_r(config, "-adcdev"),
(int) cmd_ln_float32_r(config,
"-samprate"))) == NULL)
{
NSLog(@"Failed to open audio device");
return;
}
if (ad_start_rec(ad) < 0)
{
NSLog(@"Failed to start recording");
return;
}
if (ps_start_utt(ps) < 0)
{
NSLog(@"Failed to start utterance");
return;
}
utt_started = NO;
NSDebugLog(@"Ready.... <%@, %d>", _listeningThread, [_listeningThread isCancelled]);
while([_listeningThread isCancelled] == NO && _listeningThread != nil)
{
if ((k = ad_read(ad, adbuf, 2048)) < 0)
{
NSLog(@"Failed to read audio");
break;
}
ps_process_raw(ps, adbuf, k, FALSE, FALSE);
in_speech = ps_get_in_speech(ps);
if (in_speech && !utt_started)
{
utt_started = YES;
NSDebugLog(@"Listening...");
}
if (!in_speech && utt_started)
{
/* speech -> silence transition, time to start new utterance */
ps_end_utt(ps);
hyp = ps_get_hyp(ps, NULL);
if (hyp != NULL)
{
NSString *recognizedString = [NSString stringWithCString: hyp
encoding: NSUTF8StringEncoding];
[self performSelectorOnMainThread: @selector(_recognizedWord:)
withObject: recognizedString
waitUntilDone: NO];
NSDebugLog(@"Word: %s", hyp);
}
if (ps_start_utt(ps) < 0)
{
NSLog(@"Failed to start utterance");
}
utt_started = NO;
NSDebugLog(@"Ready.... <%@, %d>", _listeningThread, [_listeningThread isCancelled]);
}
[NSThread sleepForTimeInterval: 0.01];
}
// Close everything...
ps_end_utt(ps);
ad_close(ad);
}
- (void) start
{
_listeningThread =
[[NSThread alloc] initWithTarget: self
selector: @selector(recognize)
object: nil];
[_listeningThread setName: @"Speech Recognition Loop"];
NSLog(@"Starting - Thread info for speech recognition server %@", _listeningThread);
[_listeningThread start];
}
- (void) stop
{
NSLog(@"Stop listening thread %@", _listeningThread);
[_listeningThread cancel];
RELEASE(_listeningThread);
_listeningThread = nil;
}
@end
@implementation GSSpeechRecognitionEngine (Pocketsphinx)
+ (GSSpeechRecognitionEngine*)defaultSpeechRecognitionEngine
{
return AUTORELEASE([[PocketsphinxSpeechRecognitionEngine alloc] init]);
}
@end

View file

@ -0,0 +1,12 @@
#import <Foundation/Foundation.h>
@interface GSSpeechRecognitionServer
+ (void)start;
@end
int main(void)
{
[NSAutoreleasePool new];
[GSSpeechRecognitionServer start];
return 0;
}

View file

@ -8,7 +8,11 @@ ADDITIONAL_DEPENDS = @LIBS@
# Build speech and sound.
BUILD_SPEECH=@BUILD_SPEECH@
BUILD_SPEECH_RECOGNIZER=@BUILD_SPEECH_RECOGNIZER@
BUILD_SOUND=@BUILD_SOUND@
RECOGNIZER_BASE_LIBS=@RECOGNIZER_BASE_LIBS@
RECOGNIZER_BASE_CFLAGS=@RECOGNIZER_BASE_CFLAGS@
RECOGNIZER_ENGINE_CLASS=@RECOGNIZER_ENGINE_CLASS@
# CUPS
GSCUPS_CFLAGS = @GSCUPS_CFLAGS@

20
configure vendored
View file

@ -635,6 +635,9 @@ GSCUPS_LIBS
GSCUPS_LDFLAGS
GSCUPS_CFLAGS
have_cups
RECOGNIZER_ENGINE_CLASS
RECOGNIZER_BASE_CFLAGS
RECOGNIZER_BASE_LIBS
BUILD_SPEECH_RECOGNIZER
BUILD_SPEECH
BUILD_SOUND
@ -5677,7 +5680,7 @@ fi
BUILD_SPEECH_RECOGNIZER=
# has flite, for speech synthesis.
# has pocketsphinx, for speech recognition.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ps_start_utt in -lpocketsphinx" >&5
$as_echo_n "checking for ps_start_utt in -lpocketsphinx... " >&6; }
if ${ac_cv_lib_pocketsphinx_ps_start_utt+:} false; then :
@ -5720,12 +5723,12 @@ else
have_speech_recognizer=no
fi
for ac_header in pocketsphinx/pocketsphinx.h
for ac_header in pocketsphinx/pocketsphinx_export.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "pocketsphinx/pocketsphinx.h" "ac_cv_header_pocketsphinx_pocketsphinx_h" "$ac_includes_default"
if test "x$ac_cv_header_pocketsphinx_pocketsphinx_h" = xyes; then :
ac_fn_c_check_header_mongrel "$LINENO" "pocketsphinx/pocketsphinx_export.h" "ac_cv_header_pocketsphinx_pocketsphinx_export_h" "$ac_includes_default"
if test "x$ac_cv_header_pocketsphinx_pocketsphinx_export_h" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_POCKETSPHINX_POCKETSPHINX_H 1
#define HAVE_POCKETSPHINX_POCKETSPHINX_EXPORT_H 1
_ACEOF
have_pocketsphinx=yes
else
@ -5736,10 +5739,15 @@ done
if test $have_pocketsphinx = yes -a $have_speech_recognizer = yes -a $enable_speech_recognizer = yes; then
BUILD_SPEECH_RECOGNIZER="speech_recognizer"
POCKETSPHINX_BASE_LIBS="-lpocketsphinx"
RECOGNIZER_BASE_LIBS=`pkg-config --libs pocketsphinx sphinxbase`
RECOGNIZER_BASE_CFLAGS=`pkg-config --cflags pocketsphinx sphinxbase`
RECOGNIZER_ENGINE_CLASS=PocketsphinxSpeechRecognitionEngine.m
fi
#--------------------------------------------------------------------
# Find CUPS
#--------------------------------------------------------------------

View file

@ -546,14 +546,19 @@ AC_ARG_ENABLE(speech-recognizer,
enable_speech_recognizer=yes)
BUILD_SPEECH_RECOGNIZER=
# has flite, for speech synthesis.
# has pocketsphinx, for speech recognition.
AC_CHECK_LIB(pocketsphinx, ps_start_utt, have_speech_recognizer=yes, have_speech_recognizer=no)
AC_CHECK_HEADERS(pocketsphinx/pocketsphinx.h, have_pocketsphinx=yes, have_pocketsphinx=no)
AC_CHECK_HEADERS(pocketsphinx/pocketsphinx_export.h, have_pocketsphinx=yes, have_pocketsphinx=no)
if test $have_pocketsphinx = yes -a $have_speech_recognizer = yes -a $enable_speech_recognizer = yes; then
BUILD_SPEECH_RECOGNIZER="speech_recognizer"
POCKETSPHINX_BASE_LIBS="-lpocketsphinx"
RECOGNIZER_BASE_LIBS=`pkg-config --libs pocketsphinx sphinxbase`
RECOGNIZER_BASE_CFLAGS=`pkg-config --cflags pocketsphinx sphinxbase`
RECOGNIZER_ENGINE_CLASS=PocketsphinxSpeechRecognitionEngine.m
fi
AC_SUBST(BUILD_SPEECH_RECOGNIZER)
AC_SUBST(RECOGNIZER_BASE_LIBS)
AC_SUBST(RECOGNIZER_BASE_CFLAGS)
AC_SUBST(RECOGNIZER_ENGINE_CLASS)
#--------------------------------------------------------------------
# Find CUPS