summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--GUI/GUI/GUI/Frame.cpp140
-rw-r--r--GUI/GUI/GUI/Frame.h5
-rw-r--r--GUI/GUI/GUI/PythonWrapper.cpp25
-rw-r--r--GUI/GUI/GUI/PythonWrapper.h6
-rw-r--r--GUI/package.ps13
-rw-r--r--Scripts/generate_params.py13
-rw-r--r--Scripts/generate_utils.py38
-rw-r--r--Scripts/libtastt.py42
-rw-r--r--Scripts/osc_ctrl.py40
-rw-r--r--Scripts/transcribe.py9
10 files changed, 237 insertions, 84 deletions
diff --git a/GUI/GUI/GUI/Frame.cpp b/GUI/GUI/GUI/Frame.cpp
index 2ecc255..92d02ed 100644
--- a/GUI/GUI/GUI/Frame.cpp
+++ b/GUI/GUI/GUI/Frame.cpp
@@ -16,7 +16,7 @@ namespace {
ID_NAVBAR_BUTTON_UNITY,
ID_PY_PANEL,
ID_PY_CONFIG_PANEL,
- ID_PY_CONFIG_DROPDOWN_PANEL,
+ ID_PY_APP_CONFIG_PANEL_PAIRS,
ID_PY_SETUP_BUTTON,
ID_PY_DUMP_MICS_BUTTON,
ID_PY_APP_DRAIN,
@@ -28,6 +28,8 @@ namespace {
ID_PY_APP_LANG,
ID_PY_APP_LANG_PANEL,
ID_PY_APP_MODEL,
+ ID_PY_APP_CHARS_PER_SYNC,
+ ID_PY_APP_BYTES_PER_CHAR,
ID_PY_APP_MODEL_PANEL,
ID_UNITY_PANEL,
ID_UNITY_CONFIG_PANEL,
@@ -42,6 +44,8 @@ namespace {
ID_UNITY_PARAMETERS_GENERATED_NAME,
ID_UNITY_MENU_GENERATED_NAME,
ID_UNITY_BUTTON_GEN_ANIMATOR,
+ ID_UNITY_chars_per_sync,
+ ID_UNITY_BYTES_PER_CHAR,
};
const wxString kMicChoices[] = {
@@ -180,6 +184,40 @@ namespace {
};
const size_t kNumModelChoices = sizeof(kModelChoices) / sizeof(kModelChoices[0]);
constexpr int kModelDefault = 2; // base.en
+
+ const wxString kCharsPerSync[] = {
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ "16",
+ "17",
+ "18",
+ "19",
+ "20",
+ "21",
+ "22",
+ "23",
+ "24",
+ };
+ const size_t kNumCharsPerSync = sizeof(kCharsPerSync) / sizeof(kCharsPerSync[0]);
+ // By default, use the fastest option.
+ constexpr int kCharsDefault = kNumCharsPerSync - 1;
+
+ const wxString kBytesPerChar[] = {
+ "1",
+ "2",
+ };
+ const size_t kNumBytesPerChar = sizeof(kBytesPerChar) / sizeof(kBytesPerChar[0]);
+ // Sorry international users. Optimize for English speakers, by default.
+ constexpr int kBytesDefault = 0;
} // namespace
using ::Logging::Log;
@@ -222,34 +260,52 @@ Frame::Frame()
auto* py_setup_button = new wxButton(py_config_panel, ID_PY_SETUP_BUTTON, "Set up Python virtual environment");
auto* py_dump_mics_button = new wxButton(py_config_panel, ID_PY_DUMP_MICS_BUTTON, "List input devices");
- auto* py_config_dropdown_panel = new wxPanel(py_config_panel, ID_PY_CONFIG_DROPDOWN_PANEL);
+ auto* py_app_config_panel_pairs = new wxPanel(py_config_panel, ID_PY_APP_CONFIG_PANEL_PAIRS);
{
- auto* py_app_mic = new wxChoice(py_config_dropdown_panel, ID_PY_APP_MIC, wxDefaultPosition,
+ auto* py_app_mic = new wxChoice(py_app_config_panel_pairs, ID_PY_APP_MIC, wxDefaultPosition,
wxDefaultSize, kNumMicChoices, kMicChoices);
py_app_mic->SetSelection(kMicDefault);
py_app_mic_ = py_app_mic;
- auto* py_app_lang = new wxChoice(py_config_dropdown_panel, ID_PY_APP_LANG, wxDefaultPosition,
+ auto* py_app_lang = new wxChoice(py_app_config_panel_pairs, ID_PY_APP_LANG, wxDefaultPosition,
wxDefaultSize, kNumLangChoices, kLangChoices);
py_app_lang->SetSelection(kLangDefault);
py_app_lang_ = py_app_lang;
- auto* py_app_model = new wxChoice(py_config_dropdown_panel, ID_PY_APP_MODEL, wxDefaultPosition,
+ auto* py_app_model = new wxChoice(py_app_config_panel_pairs, ID_PY_APP_MODEL, wxDefaultPosition,
wxDefaultSize, kNumModelChoices, kModelChoices);
py_app_model->SetSelection(kModelDefault);
py_app_model_ = py_app_model;
+ auto* py_app_chars_per_sync = new wxChoice(py_app_config_panel_pairs,
+ ID_PY_APP_CHARS_PER_SYNC, wxDefaultPosition,
+ wxDefaultSize, kNumCharsPerSync, kCharsPerSync);
+ py_app_chars_per_sync->SetSelection(kCharsDefault);
+ py_app_chars_per_sync_ = py_app_chars_per_sync;
+
+ auto* py_app_bytes_per_char = new wxChoice(py_app_config_panel_pairs,
+ ID_PY_APP_BYTES_PER_CHAR, wxDefaultPosition,
+ wxDefaultSize, kNumBytesPerChar, kBytesPerChar);
+ py_app_bytes_per_char->SetSelection(kBytesDefault);
+ py_app_bytes_per_char_ = py_app_bytes_per_char;
+
auto* sizer = new wxFlexGridSizer(/*cols=*/2);
- py_config_dropdown_panel->SetSizer(sizer);
+ py_app_config_panel_pairs->SetSizer(sizer);
- sizer->Add(new wxStaticText(py_config_dropdown_panel, wxID_ANY, /*label=*/"Microphone:"));
+ sizer->Add(new wxStaticText(py_app_config_panel_pairs, wxID_ANY, /*label=*/"Microphone:"));
sizer->Add(py_app_mic, /*proportion=*/0, /*flags=*/wxEXPAND);
- sizer->Add(new wxStaticText(py_config_dropdown_panel, wxID_ANY, /*label=*/"Language:"));
+ sizer->Add(new wxStaticText(py_app_config_panel_pairs, wxID_ANY, /*label=*/"Language:"));
sizer->Add(py_app_lang, /*proportion=*/0, /*flags=*/wxEXPAND);
- sizer->Add(new wxStaticText(py_config_dropdown_panel, wxID_ANY, /*label=*/"Model:"));
+ sizer->Add(new wxStaticText(py_app_config_panel_pairs, wxID_ANY, /*label=*/"Model:"));
sizer->Add(py_app_model, /*proportion=*/0, /*flags=*/wxEXPAND);
+
+ sizer->Add(new wxStaticText(py_app_config_panel_pairs, wxID_ANY, /*label=*/"Characters per sync:"));
+ sizer->Add(py_app_chars_per_sync, /*proportion=*/0, /*flags=*/wxEXPAND);
+
+ sizer->Add(new wxStaticText(py_app_config_panel_pairs, wxID_ANY, /*label=*/"Bytes per character:"));
+ sizer->Add(py_app_bytes_per_char, /*proportion=*/0, /*flags=*/wxEXPAND);
}
auto* py_app_start_button = new wxButton(py_config_panel, ID_PY_APP_START_BUTTON, "Begin transcribing");
@@ -259,7 +315,7 @@ Frame::Frame()
py_config_panel->SetSizer(sizer);
sizer->Add(py_setup_button, /*proportion=*/0, /*flags=*/wxEXPAND);
sizer->Add(py_dump_mics_button, /*proportion=*/0, /*flags=*/wxEXPAND);
- sizer->Add(py_config_dropdown_panel, /*proportion=*/0, /*flags=*/wxEXPAND);
+ sizer->Add(py_app_config_panel_pairs, /*proportion=*/0, /*flags=*/wxEXPAND);
sizer->Add(py_app_start_button, /*proportion=*/0, /*flags=*/wxEXPAND);
sizer->Add(py_app_stop_button, /*proportion=*/0, /*flags=*/wxEXPAND);
}
@@ -348,6 +404,19 @@ Frame::Frame()
unity_menu_generated_name->AppendText("TaSTT_Menu.asset");
unity_menu_generated_name_ = unity_menu_generated_name;
+ auto* unity_chars_per_sync = new wxChoice(unity_config_panel_pairs,
+ ID_UNITY_chars_per_sync, wxDefaultPosition,
+ wxDefaultSize, kNumCharsPerSync, kCharsPerSync);
+ unity_chars_per_sync->SetSelection(kCharsDefault);
+ unity_chars_per_sync_ = unity_chars_per_sync;
+
+ auto* unity_bytes_per_char = new wxChoice(unity_config_panel_pairs,
+ ID_UNITY_BYTES_PER_CHAR, wxDefaultPosition,
+ wxDefaultSize, kNumBytesPerChar, kBytesPerChar);
+ unity_bytes_per_char->SetSelection(kBytesDefault);
+ unity_bytes_per_char_ = unity_bytes_per_char;
+
+
auto* sizer = new wxFlexGridSizer(/*cols=*/2);
unity_config_panel_pairs->SetSizer(sizer);
@@ -374,6 +443,12 @@ Frame::Frame()
sizer->Add(new wxStaticText(unity_config_panel_pairs, wxID_ANY, /*label=*/"Generated menu:"));
sizer->Add(unity_menu_generated_name);
+
+ sizer->Add(new wxStaticText(unity_config_panel_pairs, wxID_ANY, /*label=*/"Characters per sync:"));
+ sizer->Add(unity_chars_per_sync, /*proportion=*/0, /*flags=*/wxEXPAND);
+
+ sizer->Add(new wxStaticText(unity_config_panel_pairs, wxID_ANY, /*label=*/"Bytes per character:"));
+ sizer->Add(unity_bytes_per_char, /*proportion=*/0, /*flags=*/wxEXPAND);
}
auto* unity_button_gen_fx = new wxButton(unity_config_panel, ID_UNITY_BUTTON_GEN_ANIMATOR, "Generate avatar assets");
@@ -506,27 +581,38 @@ void Frame::OnGenerateFX(wxCommandEvent& event)
#endif
std::filesystem::path unity_parameters_path = unity_parameters_file_picker_->GetPath().ToStdString();
#ifndef DEBUG
- if (!std::filesystem::exists(unity_parameters_path)) {
- std::ostringstream oss;
- oss << "Cannot generate FX layer: parameters do not exist at " << unity_parameters_path << std::endl;
- wxLogError(oss.str().c_str());
+ if (!std::filesystem::exists(unity_parameters_path)) {
+ std::ostringstream oss;
+ oss << "Cannot generate FX layer: parameters do not exist at " << unity_parameters_path << std::endl;
+ wxLogError(oss.str().c_str());
return;
- }
+ }
#endif
std::filesystem::path unity_menu_path = unity_menu_file_picker_->GetPath().ToStdString();
#ifndef DEBUG
- if (!std::filesystem::exists(unity_menu_path)) {
- std::ostringstream oss;
- oss << "Cannot generate FX layer: menu does not exist at " << unity_menu_path << std::endl;
- wxLogError(oss.str().c_str());
+ if (!std::filesystem::exists(unity_menu_path)) {
+ std::ostringstream oss;
+ oss << "Cannot generate FX layer: menu does not exist at " << unity_menu_path << std::endl;
+ wxLogError(oss.str().c_str());
return;
- }
+ }
#endif
std::string unity_animator_generated_dir = unity_animator_generated_dir_->GetLineText(0).ToStdString();
std::string unity_animator_generated_name = unity_animator_generated_name_->GetLineText(0).ToStdString();
std::string unity_parameters_generated_name = unity_parameters_generated_name_->GetLineText(0).ToStdString();
std::string unity_menu_generated_name = unity_menu_generated_name_->GetLineText(0).ToStdString();
+ int chars_per_sync_idx = unity_chars_per_sync_->GetSelection();
+ if (chars_per_sync_idx == wxNOT_FOUND) {
+ chars_per_sync_idx = kCharsDefault;
+ }
+ std::string chars_per_sync = kCharsPerSync[chars_per_sync_idx].ToStdString();
+ int bytes_per_char_idx = unity_bytes_per_char_->GetSelection();
+ if (bytes_per_char_idx == wxNOT_FOUND) {
+ bytes_per_char_idx = kBytesDefault;
+ }
+ std::string bytes_per_char = kBytesPerChar[bytes_per_char_idx].ToStdString();
+
std::string out;
if (!PythonWrapper::GenerateAnimator(
unity_assets_path.string(),
@@ -537,6 +623,8 @@ void Frame::OnGenerateFX(wxCommandEvent& event)
unity_animator_generated_name,
unity_parameters_generated_name,
unity_menu_generated_name,
+ chars_per_sync,
+ bytes_per_char,
unity_out_)) {
wxLogError("Failed to generate animator:\n%s\n", out.c_str());
}
@@ -572,11 +660,21 @@ void Frame::OnAppStart(wxCommandEvent& event) {
if (which_model == wxNOT_FOUND) {
which_model = kModelDefault;
}
+ int chars_per_sync_idx = unity_chars_per_sync_->GetSelection();
+ if (chars_per_sync_idx == wxNOT_FOUND) {
+ chars_per_sync_idx = kCharsDefault;
+ }
+ int bytes_per_char_idx = unity_bytes_per_char_->GetSelection();
+ if (bytes_per_char_idx == wxNOT_FOUND) {
+ bytes_per_char_idx = kBytesDefault;
+ }
wxProcess* p = PythonWrapper::StartApp(std::move(cb),
kMicChoices[which_mic].ToStdString(),
kLangChoices[which_lang].ToStdString(),
- kModelChoices[which_model].ToStdString());
+ kModelChoices[which_model].ToStdString(),
+ kCharsPerSync[chars_per_sync_idx].ToStdString(),
+ kBytesPerChar[bytes_per_char_idx].ToStdString());
if (!p) {
Log(transcribe_out_, "Failed to launch transcription engine\n");
return;
diff --git a/GUI/GUI/GUI/Frame.h b/GUI/GUI/GUI/Frame.h
index 9b94036..aebdd93 100644
--- a/GUI/GUI/GUI/Frame.h
+++ b/GUI/GUI/GUI/Frame.h
@@ -37,6 +37,11 @@ private:
wxChoice* py_app_mic_;
wxChoice* py_app_lang_;
wxChoice* py_app_model_;
+ // TODO(yum) figure out how to deduplicate these objects
+ wxChoice* py_app_chars_per_sync_;
+ wxChoice* py_app_bytes_per_char_;
+ wxChoice* unity_chars_per_sync_;
+ wxChoice* unity_bytes_per_char_;
wxProcess* py_app_;
wxTimer py_app_drain_;
diff --git a/GUI/GUI/GUI/PythonWrapper.cpp b/GUI/GUI/GUI/PythonWrapper.cpp
index 31849f5..4dda098 100644
--- a/GUI/GUI/GUI/PythonWrapper.cpp
+++ b/GUI/GUI/GUI/PythonWrapper.cpp
@@ -123,13 +123,16 @@ bool PythonWrapper::InstallPip(std::string* out) {
wxProcess* PythonWrapper::StartApp(
std::function<void(wxProcess* proc, int ret)>&& exit_callback,
- const std::string& mic, const std::string& lang, const std::string& model) {
+ const std::string& mic, const std::string& lang, const std::string& model,
+ const std::string& chars_per_sync, const std::string& bytes_per_char) {
return InvokeAsyncWithArgs({
"-u",
"Resources/Scripts/transcribe.py",
"--mic", mic,
"--lang", lang,
"--model", model,
+ "--chars_per_sync", chars_per_sync,
+ "--bytes_per_char", bytes_per_char,
},
std::move(exit_callback));
}
@@ -143,6 +146,8 @@ bool PythonWrapper::GenerateAnimator(
const std::string& unity_animator_generated_name,
const std::string& unity_parameters_generated_name,
const std::string& unity_menu_generated_name,
+ const std::string& chars_per_sync,
+ const std::string& bytes_per_char,
wxTextCtrl* out) {
// Python script locations
std::string libunity_path = "Resources/Scripts/libunity.py";
@@ -180,12 +185,6 @@ bool PythonWrapper::GenerateAnimator(
tastt_generated_dir_path / unity_animator_generated_name;
{
- /*
- if (std::filesystem::exists(tastt_generated_dir_path)) {
- Log(out, "Erasing {}\n", tastt_generated_dir_path.string());
- std::filesystem::remove_all(tastt_generated_dir_path);
- }
- */
Log(out, "Creating {}\n", tastt_generated_dir_path.string());
std::filesystem::create_directories(tastt_generated_dir_path);
}
@@ -273,7 +272,9 @@ bool PythonWrapper::GenerateAnimator(
std::string py_stdout, py_stderr;
if (InvokeWithArgs({ libtastt_path, "gen_anims",
"--gen_anim_dir", tastt_animations_path.string(),
- "--guid_map", guid_map_path.string() },
+ "--guid_map", guid_map_path.string(),
+ "--chars_per_sync", chars_per_sync,
+ "--bytes_per_char", bytes_per_char },
&py_stdout, &py_stderr)) {
Log(out, "success!\n");
Log(out, py_stdout.c_str());
@@ -297,7 +298,9 @@ bool PythonWrapper::GenerateAnimator(
if (InvokeWithArgs({ libtastt_path, "gen_fx",
"--fx_dest", tastt_fx0_path.string(),
"--gen_anim_dir", tastt_animations_path.string(),
- "--guid_map", guid_map_path.string() },
+ "--guid_map", guid_map_path.string(),
+ "--chars_per_sync", chars_per_sync,
+ "--bytes_per_char", bytes_per_char },
&py_stdout, &py_stderr)) {
Log(out, "success!\n");
Log(out, py_stdout.c_str());
@@ -394,7 +397,9 @@ bool PythonWrapper::GenerateAnimator(
std::string py_stdout, py_stderr;
if (InvokeWithArgs({ generate_params_path,
"--old_params", unity_parameters_path,
- "--new_params", tastt_params_path.string()},
+ "--new_params", tastt_params_path.string(),
+ "--chars_per_sync", chars_per_sync,
+ "--bytes_per_char", bytes_per_char },
&py_stdout, &py_stderr)) {
Log(out, "success!\n");
Log(out, py_stdout.c_str());
diff --git a/GUI/GUI/GUI/PythonWrapper.h b/GUI/GUI/GUI/PythonWrapper.h
index de5a2e4..5ce0113 100644
--- a/GUI/GUI/GUI/PythonWrapper.h
+++ b/GUI/GUI/GUI/PythonWrapper.h
@@ -38,7 +38,9 @@ namespace PythonWrapper
wxProcess* StartApp(
std::function<void(wxProcess* proc, int ret)>&& exit_callback,
- const std::string& mic, const std::string& lang, const std::string& model);
+ const std::string& mic, const std::string& lang, const std::string& model,
+ const std::string& chars_per_sync, const std::string& bytes_per_char
+ );
bool GenerateAnimator(
const std::string& unity_assets_path,
@@ -49,6 +51,8 @@ namespace PythonWrapper
const std::string& unity_animator_generated_name,
const std::string& unity_parameters_generated_name,
const std::string& unity_menu_generated_name,
+ const std::string& chars_per_sync,
+ const std::string& bytes_per_char,
wxTextCtrl* out);
};
diff --git a/GUI/package.ps1 b/GUI/package.ps1
index e4f8f3e..0941196 100644
--- a/GUI/package.ps1
+++ b/GUI/package.ps1
@@ -7,7 +7,8 @@ if (Test-Path $install_dir) {
mkdir $install_dir > $null
mkdir $install_dir/Resources > $null
cp -Recurse ../Animations TaSTT/Resources/Animations
-cp -Recurse ../Fonts TaSTT/Resources/Fonts
+mkdir TaSTT/Resources/Fonts
+cp -Recurse ../Fonts/Bitmaps TaSTT/Resources/Fonts/Bitmaps
cp -Recurse ../Images TaSTT/Resources/Images
cp -Recurse ../Python TaSTT/Resources/Python
cp -Recurse ../Scripts TaSTT/Resources/Scripts
diff --git a/Scripts/generate_params.py b/Scripts/generate_params.py
index 6c189a1..5deb17d 100644
--- a/Scripts/generate_params.py
+++ b/Scripts/generate_params.py
@@ -89,8 +89,8 @@ def generate():
params["PARAM_NAME"] = generate_utils.getSelectParam()
result += generate_utils.replaceMacros(INT_PARAM, params)
- for byte in range(0, generate_utils.BYTES_PER_CHAR):
- for i in range(0, generate_utils.NUM_LAYERS):
+ for byte in range(0, generate_utils.config.BYTES_PER_CHAR):
+ for i in range(0, generate_utils.config.CHARS_PER_SYNC):
params["PARAM_NAME"] = generate_utils.getBlendParam(i, byte)
result += generate_utils.replaceMacros(FLOAT_PARAM, params)
@@ -109,6 +109,8 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--old_params", type=str, help="The parameters to append to")
parser.add_argument("--new_params", type=str, help="The parameters to create")
+ parser.add_argument("--bytes_per_char", type=str, help="The number of bytes to use to represent each character")
+ parser.add_argument("--chars_per_sync", type=str, help="The number of characters to send on each sync event")
args = parser.parse_args()
if not args.old_params or not args.new_params:
@@ -117,5 +119,12 @@ if __name__ == "__main__":
parser.print_help()
parser.exit(1)
+ if not args.bytes_per_char or not args.chars_per_sync:
+ print("--bytes_per_char and --chars_per_sync required", file=sys.stderr)
+ parser.print_help()
+ parser.exit(1)
+ generate_utils.config.BYTES_PER_CHAR = int(args.bytes_per_char)
+ generate_utils.config.CHARS_PER_SYNC = int(args.chars_per_sync)
+
append(args.old_params, generate(), args.new_params)
diff --git a/Scripts/generate_utils.py b/Scripts/generate_utils.py
index e8fcc8b..6930782 100644
--- a/Scripts/generate_utils.py
+++ b/Scripts/generate_utils.py
@@ -6,16 +6,24 @@ def replaceMacros(lines, macro_defs):
lines = lines.replace("%" + k + "%", v)
return lines
-# Note, (BOARD_ROWS * BOARD_COLS % NUM_LAYERS) must equal 0. If not, writing to
-# the last cell will (with the current implementation) wrap around to the front
-# of the board.
-BOARD_ROWS=4
-BOARD_COLS=48
-NUM_REGIONS = 24
-CHARS_PER_CELL=256
-BYTES_PER_CHAR=2
-
-NUM_LAYERS=ceil((BOARD_ROWS * BOARD_COLS) / NUM_REGIONS)
+class Config():
+ def __init__(self):
+ self.BOARD_ROWS=4
+ self.BOARD_COLS=48
+ self.CHARS_PER_CELL=256
+ self.BYTES_PER_CHAR=2
+ self.CHARS_PER_SYNC=10
+
+ def numRegions(self, which_layer):
+ num_cells = self.BOARD_ROWS * self.BOARD_COLS
+ layers_in_last_region = num_cells % self.CHARS_PER_SYNC
+ float_result = num_cells / self.CHARS_PER_SYNC
+ if which_layer > layers_in_last_region:
+ return floor(float_result)
+ else:
+ return ceil(float_result)
+
+config = Config()
# Implementation detail. We use this parameter to return from the terminal
# state of the FX layer to the starting state.
@@ -94,7 +102,7 @@ def getBoardIndex(which_layer, select):
# We work around this by simply wrapping those animations back to the top
# of the board, and rely on the OSC controller to simply not reference
# those cells.
- return (select * NUM_LAYERS + which_layer) % (BOARD_ROWS * BOARD_COLS)
+ return (select * config.CHARS_PER_SYNC + which_layer) % (config.BOARD_ROWS * config.BOARD_COLS)
def getShaderParamByRowColByte(row, col, byte):
return "_Letter_Row%02d_Col%02d_Byte%01d" % (row, col, byte)
@@ -103,8 +111,8 @@ def getShaderParamByRowColByte(row, col, byte):
def getShaderParam(which_layer, select, byte):
index = getBoardIndex(which_layer, select)
- col = index % BOARD_COLS
- row = floor(index / BOARD_COLS)
+ col = index % config.BOARD_COLS
+ row = floor(index / config.BOARD_COLS)
return getShaderParamByRowCol(row, col, byte)
@@ -120,8 +128,8 @@ def getClearAnimationName():
def getAnimationNameByLayerAndIndex(which_layer, select, letter, nth_byte):
index = getBoardIndex(which_layer, select)
- col = index % BOARD_COLS
- row = floor(index / BOARD_COLS)
+ col = index % config.BOARD_COLS
+ row = floor(index / config.BOARD_COLS)
return "R%02dC%02dL%02dB%01d" % (row, col, letter, nth_byte)
diff --git a/Scripts/libtastt.py b/Scripts/libtastt.py
index 9efd0e9..3168517 100644
--- a/Scripts/libtastt.py
+++ b/Scripts/libtastt.py
@@ -165,9 +165,9 @@ def generateClearAnimation(anim_dir, guid_map):
letter = 0
- for byte in range(0, generate_utils.BYTES_PER_CHAR):
- for row in range(0, generate_utils.BOARD_ROWS):
- for col in range(0, generate_utils.BOARD_COLS):
+ for byte in range(0, generate_utils.config.BYTES_PER_CHAR):
+ for row in range(0, generate_utils.config.BOARD_ROWS):
+ for col in range(0, generate_utils.config.BOARD_COLS):
curve = curve_template.copy()
for keyframe in curve.mapping['curve'].mapping['m_Curve'].sequence:
keyframe.mapping['value'] = str(letter +
@@ -294,14 +294,14 @@ def generateAnimations(anim_dir, guid_map):
anim_clip.mapping['m_EditorCurves'].sequence = []
# To support more languages, we use 2 bytes per character, giving us a 64K character set.
- for byte in range(0, generate_utils.BYTES_PER_CHAR):
- for row in range(0, generate_utils.BOARD_ROWS):
+ for byte in range(0, generate_utils.config.BYTES_PER_CHAR):
+ for row in range(0, generate_utils.config.BOARD_ROWS):
print("Generating letter animations (row {}/{}) (byte {}/2)".format(row,
- generate_utils.BOARD_ROWS, byte), file=sys.stderr)
- for col in range(0, generate_utils.BOARD_COLS):
+ generate_utils.config.BOARD_ROWS, byte), file=sys.stderr)
+ for col in range(0, generate_utils.config.BOARD_COLS):
for letter in range(0, 2):
if letter == 1:
- letter = generate_utils.CHARS_PER_CELL - 1
+ letter = generate_utils.config.CHARS_PER_CELL - 1
# Make a deep copy of the templates
node = anim_node.copy()
@@ -348,9 +348,9 @@ def generateFXController(anim: libunity.UnityAnimator) -> typing.Dict[int, libun
anim.addParameter(generate_utils.getScaleParam(), float)
layers = {}
- for byte in range(0, generate_utils.BYTES_PER_CHAR):
+ for byte in range(0, generate_utils.config.BYTES_PER_CHAR):
layers[byte] = {}
- for i in range(0, generate_utils.NUM_LAYERS):
+ for i in range(0, generate_utils.config.CHARS_PER_SYNC):
anim.addParameter(generate_utils.getBlendParam(i, byte), float)
layer = anim.addLayer(generate_utils.getLayerName(i, byte))
@@ -375,7 +375,7 @@ def generateFXLayer(which_layer: int, anim: libunity.UnityAnimator, layer:
enable_param, True)
select_states = {}
- for i in range(0, generate_utils.NUM_REGIONS):
+ for i in range(0, generate_utils.config.numRegions(which_layer)):
dx = i * 200
dy = 200
@@ -387,7 +387,7 @@ def generateFXLayer(which_layer: int, anim: libunity.UnityAnimator, layer:
guid_lo = guid_map[anim_lo_path]
anim_hi_path = os.path.join(gen_anim_dir,
generate_utils.getAnimationNameByLayerAndIndex(
- which_layer, i, generate_utils.CHARS_PER_CELL - 1, byte) + \
+ which_layer, i, generate_utils.config.CHARS_PER_CELL - 1, byte) + \
".anim")
guid_hi = guid_map[anim_hi_path]
@@ -490,7 +490,7 @@ def generateFX(guid_map, gen_anim_dir):
layers = generateFXController(anim)
# TODO(yum) parallelize
- for byte in range(0, generate_utils.BYTES_PER_CHAR):
+ for byte in range(0, generate_utils.config.BYTES_PER_CHAR):
for which_layer, layer in layers[byte].items():
print("Generating layer {}/{}".format(which_layer, len(layers[byte].items())), file=sys.stderr)
generateFXLayer(which_layer, anim, layer, gen_anim_dir, byte)
@@ -547,6 +547,8 @@ def parseArgs():
"which all generated animations are placed.")
parser.add_argument("--guid_map", type=str, help="The path to a file which will store guids")
parser.add_argument("--fx_dest", type=str, help="The path at which to save the generated FX controller")
+ parser.add_argument("--bytes_per_char", type=str, help="The number of bytes to use to represent each character")
+ parser.add_argument("--chars_per_sync", type=str, help="The number of characters to send on each sync event")
args = parser.parse_args()
if not args.gen_dir:
@@ -569,6 +571,13 @@ if __name__ == "__main__":
args = parseArgs()
if args.cmd == "gen_anims":
+ if not args.bytes_per_char or not args.chars_per_sync:
+ print("--bytes_per_char and --chars_per_sync required", file=sys.stderr)
+ sys.exit(1)
+
+ generate_utils.config.BYTES_PER_CHAR = int(args.bytes_per_char)
+ generate_utils.config.CHARS_PER_SYNC = int(args.chars_per_sync)
+
guid_map = {}
with open(args.guid_map, 'rb') as f:
guid_map = pickle.load(f)
@@ -579,6 +588,13 @@ if __name__ == "__main__":
with open(args.guid_map, 'wb') as f:
pickle.dump(guid_map, f)
elif args.cmd == "gen_fx":
+ if not args.bytes_per_char or not args.chars_per_sync:
+ print("--bytes_per_char and --chars_per_sync required", file=sys.stderr)
+ sys.exit(1)
+
+ generate_utils.config.BYTES_PER_CHAR = int(args.bytes_per_char)
+ generate_utils.config.CHARS_PER_SYNC = int(args.chars_per_sync)
+
guid_map = {}
with open(args.guid_map, 'rb') as f:
guid_map = pickle.load(f)
diff --git a/Scripts/osc_ctrl.py b/Scripts/osc_ctrl.py
index a7dcc2b..21c6348 100644
--- a/Scripts/osc_ctrl.py
+++ b/Scripts/osc_ctrl.py
@@ -16,9 +16,7 @@ from generate_utils import getLayerParam
from generate_utils import getSelectParam
from generate_utils import getEnableParam
from generate_utils import getBoardIndex
-from generate_utils import NUM_LAYERS
-from generate_utils import BOARD_ROWS
-from generate_utils import BOARD_COLS
+from generate_utils import config
import emotes
@@ -53,7 +51,7 @@ state.encoding = generateEncoding()
# lines sent is a multiple of the number of rows in the board.
def encodeMessage(lines):
result = []
- lines_tmp = lines + [" "] * ((BOARD_ROWS - len(lines)) % BOARD_ROWS)
+ lines_tmp = lines + [" "] * ((config.BOARD_ROWS - len(lines)) % config.BOARD_ROWS)
for line in lines_tmp:
first_word = True
for word in line.split():
@@ -82,11 +80,11 @@ def encodeMessage(lines):
print("skip unrecognized char {}".format(char))
continue
result.append(state.encoding[char])
- result += [state.encoding[' ']] * (BOARD_COLS - len(line))
+ result += [state.encoding[' ']] * (config.BOARD_COLS - len(line))
return result
def updateCell(client, cell_idx, letter_encoded):
- for byte in range(0, generate_utils.BYTES_PER_CHAR):
+ for byte in range(0, generate_utils.config.BYTES_PER_CHAR):
addr="/avatar/parameters/" + generate_utils.getBlendParam(cell_idx, byte)
letter_remapped = (-127.5 + letter_encoded[byte]) / 127.5
client.send_message(addr, letter_remapped)
@@ -102,14 +100,14 @@ def disable(client):
# Send a cell all at once.
# `which_cell` is an integer in the range [0,NUM_REGIONS)
def sendMessageCellDiscrete(client, msg_cell, which_cell):
- empty_cell = [state.encoding[' ']] * NUM_LAYERS
+ empty_cell = [state.encoding[' ']] * generate_utils.config.CHARS_PER_SYNC
if msg_cell != empty_cell:
addr="/avatar/parameters/" + generate_utils.getSpeechNoiseToggleParam()
client.send_message(addr, True)
# Really long messages just wrap back around.
- which_cell = (which_cell % generate_utils.NUM_REGIONS)
+ which_cell = (which_cell % generate_utils.config.numRegions(0))
enable(client)
@@ -129,7 +127,7 @@ def sendMessageCellDiscrete(client, msg_cell, which_cell):
client.send_message(addr, False)
# The board is broken down into contiguous collections of characters called
-# cells. Each cell contains `NUM_LAYERS` characters. We can update one cell
+# cells. Each cell contains `CHARS_PER_SYNC` characters. We can update one cell
# every ~1.0 seconds. Going faster causes the board to display garbage to
# remote players.
def splitMessage(msg):
@@ -151,13 +149,13 @@ def splitMessage(msg):
print("word align: {}".format(word_align))
word = ' ' * word_align + word
- while len(word) > BOARD_COLS:
+ while len(word) > config.BOARD_COLS:
if len(line) != 0:
lines.append(line)
line = ""
- word_prefix = word[0:BOARD_COLS-1] + "-"
- word_suffix = word[BOARD_COLS-1:]
+ word_prefix = word[0:config.BOARD_COLS-1] + "-"
+ word_suffix = word[config.BOARD_COLS-1:]
#print("append prefix {}".format(word_prefix))
lines.append(word_prefix)
word = word_suffix
@@ -166,7 +164,7 @@ def splitMessage(msg):
line = word
continue
- if len(line) + len(" ") + len(word) <= BOARD_COLS:
+ if len(line) + len(" ") + len(word) <= config.BOARD_COLS:
line += " " + word
continue
@@ -195,7 +193,7 @@ def resizeBoard(num_lines, tx_state, shrink_only):
resize_param0 = None
resize_param1 = None
- if num_lines > BOARD_ROWS / 2:
+ if num_lines > config.BOARD_ROWS / 2:
# Board must be expanded to full size.
if shrink_only:
return
@@ -275,10 +273,10 @@ def sendMessageLazy(client, msg, tx_state):
empty_cells_sent = 0
nonempty_cells_sent = 0
- n_cells = ceil(msg_encoded_len / NUM_LAYERS)
+ n_cells = floor(msg_encoded_len / config.CHARS_PER_SYNC)
for cell in range(0, n_cells):
- cell_begin = cell * NUM_LAYERS
- cell_end = (cell + 1) * NUM_LAYERS
+ cell_begin = cell * config.CHARS_PER_SYNC
+ cell_end = (cell + 1) * config.CHARS_PER_SYNC
cell_msg = msg_encoded[cell_begin:cell_end]
last_cell_msg = []
@@ -289,7 +287,7 @@ def sendMessageLazy(client, msg, tx_state):
if cell_msg == last_cell_msg:
continue
- if cell_msg == [state.encoding[' ']] * NUM_LAYERS:
+ if cell_msg == [state.encoding[' ']] * config.CHARS_PER_SYNC:
if empty_cells_sent >= tx_state.empty_cells_to_send_per_call:
return SEND_MSG_LAZY_SENT_EMPTY
empty_cells_sent += 1
@@ -308,10 +306,10 @@ def sendMessageLazy(client, msg, tx_state):
return SEND_MSG_LAZY_DONE
def sendRawMessage(client, msg):
- n_cells = ceil(len(msg) / NUM_LAYERS)
+ n_cells = ceil(len(msg) / config.CHARS_PER_SYNC)
for cell in range(0, n_cells):
- cell_begin = cell * NUM_LAYERS
- cell_end = (cell + 1) * NUM_LAYERS
+ cell_begin = cell * config.CHARS_PER_SYNC
+ cell_end = (cell + 1) * config.CHARS_PER_SYNC
cell_msg = msg[cell_begin:cell_end]
#print("Send cell {}".format(cell))
sendMessageCellDiscrete(client, cell_msg, cell)
diff --git a/Scripts/transcribe.py b/Scripts/transcribe.py
index e883704..00ab82f 100644
--- a/Scripts/transcribe.py
+++ b/Scripts/transcribe.py
@@ -6,6 +6,7 @@ from datetime import datetime
import os
import osc_ctrl
from functools import partial
+import generate_utils
# python3 -m pip install pyaudio
# License: MIT.
import pyaudio
@@ -400,6 +401,8 @@ if __name__ == "__main__":
parser.add_argument("--mic", type=str, help="Which mic to use. Options: index, focusrite. Default: index")
parser.add_argument("--language", type=str, help="Which language to use. Ex: english, japanese, chinese, french, german.")
parser.add_argument("--model", type=str, help="Which AI model to use. Ex: tiny, base, small, medium")
+ parser.add_argument("--bytes_per_char", type=str, help="The number of bytes to use to represent each character")
+ parser.add_argument("--chars_per_sync", type=str, help="The number of characters to send on each sync event")
args = parser.parse_args()
if not args.mic:
@@ -411,5 +414,11 @@ if __name__ == "__main__":
if not args.model:
args.language = "base"
+ if not args.bytes_per_char or not args.chars_per_sync:
+ print("--bytes_per_char and --chars_per_sync required", file=sys.stderr)
+ sys.exit(1)
+ generate_utils.config.BYTES_PER_CHAR = int(args.bytes_per_char)
+ generate_utils.config.CHARS_PER_SYNC = int(args.chars_per_sync)
+
transcribeLoop(args.mic, args.language, args.model)