jamulus/src/main.cpp

799 lines
28 KiB
C++
Raw Normal View History

/******************************************************************************\
2020-01-01 15:41:43 +01:00
* Copyright (c) 2004-2020
*
* Author(s):
* Volker Fischer
*
******************************************************************************
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program 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 General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
\******************************************************************************/
#include <QApplication>
#include <QMessageBox>
#include <QDir>
#include <QTextStream>
2020-04-23 17:00:58 +02:00
#include <QTranslator>
#include "global.h"
2013-03-24 11:49:25 +01:00
#include "clientdlg.h"
#include "serverdlg.h"
#include "settings.h"
#include "testbench.h"
#include "util.h"
Add recording support with Reaper Project generation Includes the following changes * Initial .gitignore Administrative * Fix up warning message * Not all Windows file systems are case insensitive Bugfixes * (Qt5) Use QCoreApplication for headless Possible solution to get the application to run as a headless server but it loses the nice history graph, so not ideal. * Avoid ESC closing chat Because ESC shouldn't close the chat window. Or the main app window. * Add console logging support for Windows Whilst looking for the headless support, I found this idea for Windows logging. New improved version. This makes far fewer changes. ---- * Add recording support with Reaper Project generation The main feature! * New -r option to enable recording of PCM files and conversion to Reaper RPP with WAV files * New -R option to set the directory in which to create recording sessions You need to specify the -R option, there's no default... so I guess -r and -R could be combined. * New -T option to convert a session directory with PCM files into a Reaper RPP with WAV files You can use -T on "failed" sessions, if the -r option captures the PCMs but the RPP converter doesn't run for some reaon. (It was useful during development, maybe less so once things seem stable.) The recorder is implemented as a new thread with queuing from the main "real time" server thread. When a new client connects or if its audio format changes (e.g. mono to stereo), a new RIFF WAVE file is started. Each frame of decompressed audio for each client written out as LPCM to the file. When the client disconnects, the RIFF WAVE headers are updated to reflect the file length. Once all clients disconnect, the session is considered ended and a Reaper RPP file is written.
2019-04-03 19:12:45 +02:00
// Implementation **************************************************************
int main ( int argc, char** argv )
{
QTextStream& tsConsole = *( ( new ConsoleWriterFactory() )->get() );
QString strArgument;
double rDbleArgument;
// initialize all flags and string which might be changed by command line
// arguments
#if defined( SERVER_BUNDLE ) && ( defined( __APPLE__ ) || defined( __MACOSX ) )
// if we are on MacOS and we are building a server bundle, starts Jamulus in server mode
bool bIsClient = false;
#else
bool bIsClient = true;
#endif
bool bUseGUI = true;
bool bStartMinimized = false;
bool bShowComplRegConnList = false;
2015-10-17 17:37:58 +02:00
bool bDisconnectAllClients = false;
bool bUseDoubleSystemFrameSize = true; // default is 128 samples frame size
bool bShowAnalyzerConsole = false;
bool bCentServPingServerInList = false;
bool bNoAutoJackConnect = false;
bool bUseTranslation = false;
int iNumServerChannels = DEFAULT_USED_NUM_CHANNELS;
2020-03-22 18:45:00 +01:00
int iMaxDaysHistory = DEFAULT_DAYS_HISTORY;
int iCtrlMIDIChannel = INVALID_MIDI_CH;
quint16 iPortNumber = LLCON_DEFAULT_PORT_NUMBER;
ELicenceType eLicenceType = LT_NO_LICENCE;
QString strConnOnStartupAddress = "";
QString strIniFileName = "";
QString strHTMLStatusFileName = "";
QString strServerName = "";
QString strLoggingFileName = "";
QString strHistoryFileName = "";
Add recording support with Reaper Project generation Includes the following changes * Initial .gitignore Administrative * Fix up warning message * Not all Windows file systems are case insensitive Bugfixes * (Qt5) Use QCoreApplication for headless Possible solution to get the application to run as a headless server but it loses the nice history graph, so not ideal. * Avoid ESC closing chat Because ESC shouldn't close the chat window. Or the main app window. * Add console logging support for Windows Whilst looking for the headless support, I found this idea for Windows logging. New improved version. This makes far fewer changes. ---- * Add recording support with Reaper Project generation The main feature! * New -r option to enable recording of PCM files and conversion to Reaper RPP with WAV files * New -R option to set the directory in which to create recording sessions You need to specify the -R option, there's no default... so I guess -r and -R could be combined. * New -T option to convert a session directory with PCM files into a Reaper RPP with WAV files You can use -T on "failed" sessions, if the -r option captures the PCMs but the RPP converter doesn't run for some reaon. (It was useful during development, maybe less so once things seem stable.) The recorder is implemented as a new thread with queuing from the main "real time" server thread. When a new client connects or if its audio format changes (e.g. mono to stereo), a new RIFF WAVE file is started. Each frame of decompressed audio for each client written out as LPCM to the file. When the client disconnects, the RIFF WAVE headers are updated to reflect the file length. Once all clients disconnect, the session is considered ended and a Reaper RPP file is written.
2019-04-03 19:12:45 +02:00
QString strRecordingDirName = "";
QString strCentralServer = "";
QString strServerInfo = "";
QString strWelcomeMessage = "";
QString strClientName = APP_NAME;
// QT docu: argv()[0] is the program name, argv()[1] is the first
// argument and argv()[argc()-1] is the last argument.
// Start with first argument, therefore "i = 1"
for ( int i = 1; i < argc; i++ )
{
// Server mode flag ----------------------------------------------------
if ( GetFlagArgument ( argv,
i,
"-s",
"--server" ) )
{
bIsClient = false;
tsConsole << "- server mode chosen" << endl;
continue;
}
// Use GUI flag --------------------------------------------------------
if ( GetFlagArgument ( argv,
i,
"-n",
"--nogui" ) )
{
bUseGUI = false;
tsConsole << "- no GUI mode chosen" << endl;
continue;
}
// Use licence flag ----------------------------------------------------
if ( GetFlagArgument ( argv,
i,
"-L",
"--licence" ) )
{
// right now only the creative commons licence is supported
eLicenceType = LT_CREATIVECOMMONS;
tsConsole << "- licence required" << endl;
continue;
}
// Use 64 samples frame size mode ----------------------------------------------------
if ( GetFlagArgument ( argv,
i,
"-F",
"--fastupdate" ) )
{
bUseDoubleSystemFrameSize = false; // 64 samples frame size
tsConsole << "- using " << SYSTEM_FRAME_SIZE_SAMPLES << " samples frame size mode" << endl;
continue;
}
// Maximum number of channels ------------------------------------------
if ( GetNumericArgument ( tsConsole,
argc,
argv,
i,
"-u",
"--numchannels",
1,
MAX_NUM_CHANNELS,
rDbleArgument ) )
{
iNumServerChannels = static_cast<int> ( rDbleArgument );
tsConsole << "- maximum number of channels: "
<< iNumServerChannels << endl;
continue;
}
2020-03-22 20:24:30 +01:00
// Maximum days in history display -------------------------------------
if ( GetNumericArgument ( tsConsole,
argc,
argv,
i,
"-D",
"--histdays",
1,
366,
rDbleArgument ) )
{
iMaxDaysHistory = static_cast<int> ( rDbleArgument );
tsConsole << "- maximum days in history display: "
<< iMaxDaysHistory << endl;
continue;
}
// Start minimized -----------------------------------------------------
if ( GetFlagArgument ( argv,
i,
"-z",
"--startminimized" ) )
{
bStartMinimized = true;
tsConsole << "- start minimized enabled" << endl;
continue;
}
// Ping servers in list for central server -----------------------------
if ( GetFlagArgument ( argv,
i,
"-g",
"--pingservers" ) )
{
bCentServPingServerInList = true;
tsConsole << "- ping servers in slave server list" << endl;
continue;
}
// Disabling auto Jack connections -------------------------------------
if ( GetFlagArgument ( argv,
i,
"-j",
"--nojackconnect" ) )
{
bNoAutoJackConnect = true;
tsConsole << "- disable auto Jack connections" << endl;
continue;
}
// Enable translations -------------------------------------------------
// Undocumented debugging command line argument: Enable translations
// (since translation is still WIP, it is not enabled by default but
// must be enabled with this undocumented command line flag)
if ( GetFlagArgument ( argv,
i,
"--translation", // no short form
"--translation" ) )
{
bUseTranslation = true;
tsConsole << "- translations enabled" << endl;
continue;
}
// Show all registered servers in the server list ----------------------
// Undocumented debugging command line argument: Show all registered
// servers in the server list regardless if a ping to the server is
// possible or not.
if ( GetFlagArgument ( argv,
i,
"--showallservers", // no short form
"--showallservers" ) )
{
bShowComplRegConnList = true;
tsConsole << "- show all registered servers in server list" << endl;
continue;
}
2015-10-17 17:37:58 +02:00
// Disconnect all clients (emergency mode) -----------------------------
// Undocumented debugging command line argument: Needed to disconnect
// an unwanted client.
if ( GetFlagArgument ( argv,
i,
"--disconnectall", // no short form
"--disconnectall" ) )
{
bDisconnectAllClients = true;
tsConsole << "- disconnect all clients" << endl;
continue;
}
// Show analyzer console -----------------------------------------------
// Undocumented debugging command line argument: Show the analyzer
// console to debug network buffer properties.
if ( GetFlagArgument ( argv,
i,
"--showanalyzerconsole", // no short form
"--showanalyzerconsole" ) )
{
bShowAnalyzerConsole = true;
tsConsole << "- show analyzer console" << endl;
continue;
}
// Controller MIDI channel ---------------------------------------------
if ( GetNumericArgument ( tsConsole,
argc,
argv,
i,
"--ctrlmidich", // no short form
"--ctrlmidich",
0,
15,
rDbleArgument ) )
{
iCtrlMIDIChannel = static_cast<int> ( rDbleArgument );
tsConsole << "- selected controller MIDI channel: " << iCtrlMIDIChannel << endl;
continue;
}
// Use logging ---------------------------------------------------------
if ( GetStringArgument ( tsConsole,
argc,
argv,
i,
"-l",
"--log",
strArgument ) )
{
strLoggingFileName = strArgument;
tsConsole << "- logging file name: " << strLoggingFileName << endl;
continue;
}
// Port number ---------------------------------------------------------
if ( GetNumericArgument ( tsConsole,
argc,
argv,
i,
"-p",
"--port",
0,
65535,
rDbleArgument ) )
{
iPortNumber = static_cast<quint16> ( rDbleArgument );
tsConsole << "- selected port number: " << iPortNumber << endl;
continue;
}
// HTML status file ----------------------------------------------------
if ( GetStringArgument ( tsConsole,
argc,
argv,
i,
"-m",
"--htmlstatus",
strArgument ) )
{
strHTMLStatusFileName = strArgument;
tsConsole << "- HTML status file name: " << strHTMLStatusFileName << endl;
continue;
}
if ( GetStringArgument ( tsConsole,
argc,
argv,
i,
"-a",
"--servername",
strArgument ) )
{
strServerName = strArgument;
tsConsole << "- server name for HTML status file: " << strServerName << endl;
continue;
}
2020-04-30 22:03:01 +02:00
// Client Name ---------------------------------------------------------
if ( GetStringArgument ( tsConsole,
argc,
argv,
i,
"--clientname",
"--clientname",
strArgument ) )
{
strClientName = QString ( APP_NAME ) + " " + strArgument;
tsConsole << "- client name: " << strClientName << endl;
continue;
}
// Server history file name --------------------------------------------
if ( GetStringArgument ( tsConsole,
argc,
argv,
i,
"-y",
"--history",
strArgument ) )
{
strHistoryFileName = strArgument;
tsConsole << "- history file name: " << strHistoryFileName << endl;
continue;
}
Add recording support with Reaper Project generation Includes the following changes * Initial .gitignore Administrative * Fix up warning message * Not all Windows file systems are case insensitive Bugfixes * (Qt5) Use QCoreApplication for headless Possible solution to get the application to run as a headless server but it loses the nice history graph, so not ideal. * Avoid ESC closing chat Because ESC shouldn't close the chat window. Or the main app window. * Add console logging support for Windows Whilst looking for the headless support, I found this idea for Windows logging. New improved version. This makes far fewer changes. ---- * Add recording support with Reaper Project generation The main feature! * New -r option to enable recording of PCM files and conversion to Reaper RPP with WAV files * New -R option to set the directory in which to create recording sessions You need to specify the -R option, there's no default... so I guess -r and -R could be combined. * New -T option to convert a session directory with PCM files into a Reaper RPP with WAV files You can use -T on "failed" sessions, if the -r option captures the PCMs but the RPP converter doesn't run for some reaon. (It was useful during development, maybe less so once things seem stable.) The recorder is implemented as a new thread with queuing from the main "real time" server thread. When a new client connects or if its audio format changes (e.g. mono to stereo), a new RIFF WAVE file is started. Each frame of decompressed audio for each client written out as LPCM to the file. When the client disconnects, the RIFF WAVE headers are updated to reflect the file length. Once all clients disconnect, the session is considered ended and a Reaper RPP file is written.
2019-04-03 19:12:45 +02:00
// Recording directory -------------------------------------------------
if ( GetStringArgument ( tsConsole,
argc,
argv,
i,
"-R",
"--recording",
Add recording support with Reaper Project generation Includes the following changes * Initial .gitignore Administrative * Fix up warning message * Not all Windows file systems are case insensitive Bugfixes * (Qt5) Use QCoreApplication for headless Possible solution to get the application to run as a headless server but it loses the nice history graph, so not ideal. * Avoid ESC closing chat Because ESC shouldn't close the chat window. Or the main app window. * Add console logging support for Windows Whilst looking for the headless support, I found this idea for Windows logging. New improved version. This makes far fewer changes. ---- * Add recording support with Reaper Project generation The main feature! * New -r option to enable recording of PCM files and conversion to Reaper RPP with WAV files * New -R option to set the directory in which to create recording sessions You need to specify the -R option, there's no default... so I guess -r and -R could be combined. * New -T option to convert a session directory with PCM files into a Reaper RPP with WAV files You can use -T on "failed" sessions, if the -r option captures the PCMs but the RPP converter doesn't run for some reaon. (It was useful during development, maybe less so once things seem stable.) The recorder is implemented as a new thread with queuing from the main "real time" server thread. When a new client connects or if its audio format changes (e.g. mono to stereo), a new RIFF WAVE file is started. Each frame of decompressed audio for each client written out as LPCM to the file. When the client disconnects, the RIFF WAVE headers are updated to reflect the file length. Once all clients disconnect, the session is considered ended and a Reaper RPP file is written.
2019-04-03 19:12:45 +02:00
strArgument ) )
{
strRecordingDirName = strArgument;
tsConsole << "- recording directory name: " << strRecordingDirName << endl;
continue;
}
// Central server ------------------------------------------------------
if ( GetStringArgument ( tsConsole,
argc,
argv,
i,
"-e",
"--centralserver",
strArgument ) )
{
strCentralServer = strArgument;
tsConsole << "- central server: " << strCentralServer << endl;
continue;
}
// Server info ---------------------------------------------------------
if ( GetStringArgument ( tsConsole,
argc,
argv,
i,
"-o",
"--serverinfo",
strArgument ) )
{
strServerInfo = strArgument;
tsConsole << "- server info: " << strServerInfo << endl;
continue;
}
// Server welcome message ----------------------------------------------
if ( GetStringArgument ( tsConsole,
argc,
argv,
i,
"-w",
"--welcomemessage",
strArgument ) )
{
strWelcomeMessage = strArgument;
tsConsole << "- welcome message: " << strWelcomeMessage << endl;
continue;
}
// Initialization file -------------------------------------------------
if ( GetStringArgument ( tsConsole,
argc,
argv,
i,
"-i",
"--inifile",
strArgument ) )
{
strIniFileName = strArgument;
tsConsole << "- initialization file name: " << strIniFileName << endl;
continue;
}
// Connect on startup --------------------------------------------------
if ( GetStringArgument ( tsConsole,
argc,
argv,
i,
"-c",
"--connect",
strArgument ) )
{
strConnOnStartupAddress = strArgument;
tsConsole << "- connect on startup to address: " << strConnOnStartupAddress << endl;
continue;
}
// Version number ------------------------------------------------------
if ( ( !strcmp ( argv[i], "--version" ) ) ||
( !strcmp ( argv[i], "-v" ) ) )
{
tsConsole << CAboutDlg::GetVersionAndNameStr ( false ) << endl;
exit ( 1 );
}
// Help (usage) flag ---------------------------------------------------
if ( ( !strcmp ( argv[i], "--help" ) ) ||
( !strcmp ( argv[i], "-h" ) ) ||
( !strcmp ( argv[i], "-?" ) ) )
{
const QString strHelp = UsageArguments ( argv );
tsConsole << strHelp << endl;
exit ( 1 );
}
// Unknown option ------------------------------------------------------
tsConsole << argv[0] << ": ";
tsConsole << "Unknown option '" <<
argv[i] << "' -- use '--help' for help" << endl;
// clicking on the Mac application bundle, the actual application
// is called with weird command line args -> do not exit on these
#if !( defined ( __APPLE__ ) || defined ( __MACOSX ) )
exit ( 1 );
#endif
}
2020-04-23 17:00:58 +02:00
// Dependencies ------------------------------------------------------------
// per definition: if we are in "GUI" server mode and no central server
// address is given, we use the default central server address
if ( !bIsClient && bUseGUI && strCentralServer.isEmpty() )
{
strCentralServer = DEFAULT_SERVER_ADDRESS;
}
2020-04-30 22:03:01 +02:00
// Application/GUI setup ---------------------------------------------------
// Application object
if ( !bUseGUI && !strHistoryFileName.isEmpty() )
Add recording support with Reaper Project generation Includes the following changes * Initial .gitignore Administrative * Fix up warning message * Not all Windows file systems are case insensitive Bugfixes * (Qt5) Use QCoreApplication for headless Possible solution to get the application to run as a headless server but it loses the nice history graph, so not ideal. * Avoid ESC closing chat Because ESC shouldn't close the chat window. Or the main app window. * Add console logging support for Windows Whilst looking for the headless support, I found this idea for Windows logging. New improved version. This makes far fewer changes. ---- * Add recording support with Reaper Project generation The main feature! * New -r option to enable recording of PCM files and conversion to Reaper RPP with WAV files * New -R option to set the directory in which to create recording sessions You need to specify the -R option, there's no default... so I guess -r and -R could be combined. * New -T option to convert a session directory with PCM files into a Reaper RPP with WAV files You can use -T on "failed" sessions, if the -r option captures the PCMs but the RPP converter doesn't run for some reaon. (It was useful during development, maybe less so once things seem stable.) The recorder is implemented as a new thread with queuing from the main "real time" server thread. When a new client connects or if its audio format changes (e.g. mono to stereo), a new RIFF WAVE file is started. Each frame of decompressed audio for each client written out as LPCM to the file. When the client disconnects, the RIFF WAVE headers are updated to reflect the file length. Once all clients disconnect, the session is considered ended and a Reaper RPP file is written.
2019-04-03 19:12:45 +02:00
{
2019-05-19 09:30:49 +02:00
tsConsole << "Qt5 requires a windowing system to paint a JPEG image; image will use SVG" << endl;
Add recording support with Reaper Project generation Includes the following changes * Initial .gitignore Administrative * Fix up warning message * Not all Windows file systems are case insensitive Bugfixes * (Qt5) Use QCoreApplication for headless Possible solution to get the application to run as a headless server but it loses the nice history graph, so not ideal. * Avoid ESC closing chat Because ESC shouldn't close the chat window. Or the main app window. * Add console logging support for Windows Whilst looking for the headless support, I found this idea for Windows logging. New improved version. This makes far fewer changes. ---- * Add recording support with Reaper Project generation The main feature! * New -r option to enable recording of PCM files and conversion to Reaper RPP with WAV files * New -R option to set the directory in which to create recording sessions You need to specify the -R option, there's no default... so I guess -r and -R could be combined. * New -T option to convert a session directory with PCM files into a Reaper RPP with WAV files You can use -T on "failed" sessions, if the -r option captures the PCMs but the RPP converter doesn't run for some reaon. (It was useful during development, maybe less so once things seem stable.) The recorder is implemented as a new thread with queuing from the main "real time" server thread. When a new client connects or if its audio format changes (e.g. mono to stereo), a new RIFF WAVE file is started. Each frame of decompressed audio for each client written out as LPCM to the file. When the client disconnects, the RIFF WAVE headers are updated to reflect the file length. Once all clients disconnect, the session is considered ended and a Reaper RPP file is written.
2019-04-03 19:12:45 +02:00
}
QCoreApplication* pApp = bUseGUI
Add recording support with Reaper Project generation Includes the following changes * Initial .gitignore Administrative * Fix up warning message * Not all Windows file systems are case insensitive Bugfixes * (Qt5) Use QCoreApplication for headless Possible solution to get the application to run as a headless server but it loses the nice history graph, so not ideal. * Avoid ESC closing chat Because ESC shouldn't close the chat window. Or the main app window. * Add console logging support for Windows Whilst looking for the headless support, I found this idea for Windows logging. New improved version. This makes far fewer changes. ---- * Add recording support with Reaper Project generation The main feature! * New -r option to enable recording of PCM files and conversion to Reaper RPP with WAV files * New -R option to set the directory in which to create recording sessions You need to specify the -R option, there's no default... so I guess -r and -R could be combined. * New -T option to convert a session directory with PCM files into a Reaper RPP with WAV files You can use -T on "failed" sessions, if the -r option captures the PCMs but the RPP converter doesn't run for some reaon. (It was useful during development, maybe less so once things seem stable.) The recorder is implemented as a new thread with queuing from the main "real time" server thread. When a new client connects or if its audio format changes (e.g. mono to stereo), a new RIFF WAVE file is started. Each frame of decompressed audio for each client written out as LPCM to the file. When the client disconnects, the RIFF WAVE headers are updated to reflect the file length. Once all clients disconnect, the session is considered ended and a Reaper RPP file is written.
2019-04-03 19:12:45 +02:00
? new QApplication ( argc, argv )
: new QCoreApplication ( argc, argv );
#ifdef _WIN32
// set application priority class -> high priority
SetPriorityClass ( GetCurrentProcess(), HIGH_PRIORITY_CLASS );
// For accessible support we need to add a plugin to qt. The plugin has to
2013-03-24 11:49:25 +01:00
// be located in the install directory of the software by the installer.
// Here, we set the path to our application path.
QDir ApplDir ( QApplication::applicationDirPath() );
pApp->addLibraryPath ( QString ( ApplDir.absolutePath() ) );
#endif
// init resources
Q_INIT_RESOURCE(resources);
// load translations
QTranslator myappTranslator;
if ( bUseGUI && bUseTranslation )
{
if ( myappTranslator.load ( ":/translations/translation.qm" ) )
{
pApp->installTranslator ( &myappTranslator );
}
}
2020-04-23 17:00:58 +02:00
// TEST -> activate the following line to activate the test bench,
//CTestbench Testbench ( "127.0.0.1", LLCON_DEFAULT_PORT_NUMBER );
try
{
if ( bIsClient )
{
// Client:
// actual client object
CClient Client ( iPortNumber,
strConnOnStartupAddress,
iCtrlMIDIChannel,
bNoAutoJackConnect,
strClientName );
// load settings from init-file
CSettings Settings ( &Client, strIniFileName );
Settings.Load();
if ( bUseGUI )
{
// GUI object
CClientDlg ClientDlg ( &Client,
&Settings,
strConnOnStartupAddress,
bShowComplRegConnList,
bShowAnalyzerConsole,
2019-04-12 18:04:28 +02:00
nullptr,
Qt::Window );
// show dialog
ClientDlg.show();
pApp->exec();
}
else
{
// only start application without using the GUI
tsConsole << CAboutDlg::GetVersionAndNameStr ( false ) << endl;
pApp->exec();
}
}
else
{
// Server:
// actual server object
CServer Server ( iNumServerChannels,
iMaxDaysHistory,
strLoggingFileName,
iPortNumber,
strHTMLStatusFileName,
strHistoryFileName,
strServerName,
strCentralServer,
strServerInfo,
strWelcomeMessage,
Add recording support with Reaper Project generation Includes the following changes * Initial .gitignore Administrative * Fix up warning message * Not all Windows file systems are case insensitive Bugfixes * (Qt5) Use QCoreApplication for headless Possible solution to get the application to run as a headless server but it loses the nice history graph, so not ideal. * Avoid ESC closing chat Because ESC shouldn't close the chat window. Or the main app window. * Add console logging support for Windows Whilst looking for the headless support, I found this idea for Windows logging. New improved version. This makes far fewer changes. ---- * Add recording support with Reaper Project generation The main feature! * New -r option to enable recording of PCM files and conversion to Reaper RPP with WAV files * New -R option to set the directory in which to create recording sessions You need to specify the -R option, there's no default... so I guess -r and -R could be combined. * New -T option to convert a session directory with PCM files into a Reaper RPP with WAV files You can use -T on "failed" sessions, if the -r option captures the PCMs but the RPP converter doesn't run for some reaon. (It was useful during development, maybe less so once things seem stable.) The recorder is implemented as a new thread with queuing from the main "real time" server thread. When a new client connects or if its audio format changes (e.g. mono to stereo), a new RIFF WAVE file is started. Each frame of decompressed audio for each client written out as LPCM to the file. When the client disconnects, the RIFF WAVE headers are updated to reflect the file length. Once all clients disconnect, the session is considered ended and a Reaper RPP file is written.
2019-04-03 19:12:45 +02:00
strRecordingDirName,
bCentServPingServerInList,
2015-10-17 17:37:58 +02:00
bDisconnectAllClients,
bUseDoubleSystemFrameSize,
eLicenceType );
if ( bUseGUI )
{
// load settings from init-file
CSettings Settings ( &Server, strIniFileName );
Settings.Load();
// update server list AFTER restoring the settings from the
// settings file
Server.UpdateServerList();
// GUI object for the server
2013-03-24 16:42:23 +01:00
CServerDlg ServerDlg ( &Server,
&Settings,
bStartMinimized,
2019-04-12 18:04:28 +02:00
nullptr,
2013-03-24 16:42:23 +01:00
Qt::Window );
2011-05-25 22:00:54 +02:00
// show dialog (if not the minimized flag is set)
if ( !bStartMinimized )
{
ServerDlg.show();
}
pApp->exec();
}
else
{
// only start application without using the GUI
tsConsole << CAboutDlg::GetVersionAndNameStr ( false ) << endl;
// update serverlist
Server.UpdateServerList();
pApp->exec();
}
}
}
catch ( CGenErr generr )
{
// show generic error
if ( bUseGUI )
{
2019-04-12 18:04:28 +02:00
QMessageBox::critical ( nullptr,
APP_NAME,
generr.GetErrorText(),
"Quit",
2019-04-12 18:04:28 +02:00
nullptr );
}
else
{
tsConsole << generr.GetErrorText() << endl;
}
}
return 0;
}
/******************************************************************************\
* Command Line Argument Parsing *
\******************************************************************************/
QString UsageArguments ( char **argv )
{
return
"Usage: " + QString ( argv[0] ) + " [option] [optional argument]\n"
"\nRecognized options:\n"
" -h, -?, --help display this help text and exit\n"
" -i, --inifile initialization file name\n"
" -n, --nogui disable GUI\n"
" -p, --port set your local port number\n"
" -v, --version output version information and exit\n"
"\nServer only:\n"
" -a, --servername server name, required for HTML status\n"
" -D, --histdays number of days of history to display\n"
" -e, --centralserver address of the central server\n"
" -F, --fastupdate use 64 samples frame size mode\n"
" -g, --pingservers ping servers in list to keep NAT port open\n"
" (central server only)\n"
" -l, --log enable logging, set file name\n"
" -L, --licence a licence must be accepted on a new\n"
" connection\n"
" -m, --htmlstatus enable HTML status file, set file name\n"
" -o, --serverinfo infos of the server(s) in the format:\n"
" [name];[city];[country as QLocale ID]; ...\n"
" [server1 address];[server1 name]; ...\n"
" [server1 city]; ...\n"
" [server1 country as QLocale ID]; ...\n"
" [server2 address]; ...\n"
" -R, --recording enables recording and sets directory to contain\n"
" recorded jams\n"
" -s, --server start server\n"
" -u, --numchannels maximum number of channels\n"
" -w, --welcomemessage welcome message on connect\n"
" -y, --history enable connection history and set file name\n"
" -z, --startminimized start minimizied\n"
"\nClient only:\n"
" -c, --connect connect to given server address on startup\n"
" -j, --nojackconnect disable auto Jack connections\n"
" --ctrlmidich MIDI controller channel to listen\n"
2020-04-30 22:03:01 +02:00
" --clientname client name (window title and jack client name)\n"
"\nExample: " + QString ( argv[0] ) + " -s -inifile myinifile.ini\n";
}
bool GetFlagArgument ( char** argv,
int& i,
QString strShortOpt,
QString strLongOpt )
{
if ( ( !strShortOpt.compare ( argv[i] ) ) ||
( !strLongOpt.compare ( argv[i] ) ) )
{
return true;
}
else
{
return false;
}
}
bool GetStringArgument ( QTextStream& tsConsole,
int argc,
char** argv,
int& i,
QString strShortOpt,
QString strLongOpt,
QString& strArg )
{
if ( ( !strShortOpt.compare ( argv[i] ) ) ||
( !strLongOpt.compare ( argv[i] ) ) )
{
if ( ++i >= argc )
{
tsConsole << argv[0] << ": ";
tsConsole << "'" << strLongOpt << "' needs a string argument" << endl;
exit ( 1 );
}
strArg = argv[i];
return true;
}
else
{
return false;
}
}
bool GetNumericArgument ( QTextStream& tsConsole,
int argc,
char** argv,
int& i,
QString strShortOpt,
QString strLongOpt,
double rRangeStart,
double rRangeStop,
double& rValue )
{
if ( ( !strShortOpt.compare ( argv[i] ) ) ||
( !strLongOpt.compare ( argv[i] ) ) )
{
if ( ++i >= argc )
{
tsConsole << argv[0] << ": ";
tsConsole << "'" <<
strLongOpt << "' needs a numeric argument between " <<
rRangeStart << " and " << rRangeStop << endl;
exit ( 1 );
}
char *p;
rValue = strtod ( argv[i], &p );
if ( *p ||
( rValue < rRangeStart ) ||
( rValue > rRangeStop ) )
{
tsConsole << argv[0] << ": ";
tsConsole << "'" <<
strLongOpt << "' needs a numeric argument between " <<
rRangeStart << " and " << rRangeStop << endl;
exit ( 1 );
}
return true;
}
else
{
return false;
}
}