2019-04-09 21:26:13

Hey folks, I'm trying to port my Love2D speech code over to Windows and am having a few issues. Things work fine under Linux, and I lifted some Tolk Lua FFI code from Pokeymon Crystal Access, but thus far things aren't working at all under Windows.

I'll skip over my battles with the graphics on my VM. I thought I'd create a test game and try running it under my 32-bit Wine prefix. So I grabbed 32-bit Love2D and the Tolk DLLs from here:

https://ci.appveyor.com/api/projects/dk … nch=master

I then copied the DLLs out of the x86 directory into my game's directory and tried running it, but Wine threw an "EXE format error: %1" when trying to load Tolk.dll.

It's almost as if the Tolk DLLs in the x86 directory are corrupt, though I've downloaded them twice now. I'm actually wondering if the DLLs in the x86 directory are 64-bit, and indeed someone at least got to a black screen running my game under 64-bit Love, but I don't know how to tell if a DLL is 32-bit or 64-bit.

Are these Tolk DLLs getting incorrectly packaged in the wrong directory, and should I file a Tolk issue? Or am I on the wrong path with this?

I'll update this thread as the debugging progresses, but I have to break for a meeting and won't be able to get back to this for a bit. Thanks for any help.

Thumbs up

2019-04-09 21:33:59

Aww, should've checked GitHub issues first. That is indeed the problem.

Are the *other* DLLs in the x86 directory 32-bit? And does someone have a 32-bit tolk.dll they could send me?

Or should I even *bother* building 32-bit games? I mean, even my cheap Android phone is 64-bit, as are both my Raspberry Pis and my Tinkerboard. smile

Thumbs up

2019-04-09 22:20:08

The changes appear to be recent, febuary I think, some changes to appveyor and a new build process. Fortunately I have an earlier version around that works, if you just need the 32 bit dll's you can grab a test script off my repo [here]. Or if you prefer I can upload my full copy of the Tolk archive.

-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer

Thumbs up

2019-04-09 22:49:03

Got it, thanks! Found a 32-bit Tolk.dll in my local installation of New Horizons.

No one else showed for my meeting, so I skipped out early and fought through what was needed to get speech support working under Win32. I can confirm that, with the new speech.lua, my code ran unmodified under both Windows and Linux--at least, it runs under Wine.

I think this engine is well worth checking out for anyone wanting to write audio games on multiple platforms but not wanting to find and assemble a set of working libraries.

Thumbs up

2019-04-09 23:06:24

Wait, the DLLs in x86 are 64-bit? Damn, that solves a problem I was having with QT involving Tolk and my app crashing whenever I opened a particular dialog! (Not really sure why it was crashing only in *that* dialog...)

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.

Thumbs up

2019-04-10 18:33:19

Getting tolk was extremely painless for me to get working under my copy of love. Here's what I did for those who want to know:
* Tolk has a tolk lua package over at https://github.com/dkager/tolk/blob/mas … a/Tolk.lua. Go get it.
* Place tolk.lua in the same directory where main.lua is
* Place all Tolk libraries in ..
* Open main.lua and add the following code

tolk = require "tolk"
function love.load()
tolk.Load()
-- error out if we can't load Tolk (not recommended if you want sited people to play)
if not tolk.IsLoaded() then
error("Can't load Tolk!")
end
end

Then, wherever you want Tolk to speak:

tolk.Output(text)
-- or
tolk.Output(text, interrupt)

* Run love with your game and your good!

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.

Thumbs up

2019-04-10 20:41:51 (edited by Ethin 2019-04-10 20:49:06)

OK, now I have my own problem. I have an audio.zip file containing all my audio files. I mount the file:
if not love.filesystem.mount("audio.zip", "audio") then
-- handle error
end
I then run the following function on the mounted directory:
function recursiveEnumerate(folder, fileTree)
    local lfs = love.filesystem
    local filesTable = lfs.getDirectoryItems(folder)
    for i, v in ipairs(filesTable) do
        local file = folder.."/"..v
        local info = lfs.getInfo(file)
        if info.type == lfs.file then
            fileTree = fileTree.insert(fileTree, file)
        elseif info.type == lfs.directory then
            fileTree = recursiveEnumerate(file, fileTree)
        end
    end
    return fileTree
end
Yes, thank you, LOVE Wiki.
I then iterate through the table:
for k, file in ipairs(recursiveEnumerate("audio/audio", {})) do
sounds[file] = love.sound.newSoundData(file)
end
(The sounds table is created globally.)
But here's where the problems start. As soon as I type "lovec lgame" (which is my game...) it just sits there, then crashes for no apparent reason. No lua error, no error message dialog, nothing. This is a 64-bit version, if I'm not mistaken, so even if I am going above the 4 GB mark this shouldn't be happening.
Edit: OK, I see why now. Its not scanning the directories properly... Huh...
Edit 2: fixed!

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.

Thumbs up

2019-04-10 21:33:01 (edited by ogomez92 2019-04-10 21:33:35)

Tolk is only windows right? What about Mac OS speech? Hmmmmmm, I'll see if I can come up with anything. Not enough time at the moment.

Thumbs up

2019-04-11 02:52:34

This is my speech code. Works on Linux and under Wine. If you can get it working under MacOS too, I'd appreciate the contribution. Note that this is the first Lua I've written in a decade or so, so make of it what you will.

-- The Windows portions of this code were adapted from the Pokecrystal Access scripts by Tyler Spivey.
-- Original scripts: https://github.com/tspivey/pokecrystal-access

local ffi = require("ffi")

ffi.cdef[[
typedef enum {
  SPD_MODE_SINGLE = 0,
  SPD_MODE_THREADED = 1
} SPDConnectionMode;

typedef enum {
  SPD_IMPORTANT = 1,
  SPD_MESSAGE = 2,
  SPD_TEXT = 3,
  SPD_NOTIFICATION = 4,
  SPD_PROGRESS = 5
} SPDPriority;

void *spd_open(const char *client_name, const char *connection_name, const char *user_name, SPDConnectionMode mode);

int spd_say(void *connection, SPDPriority priority, const char *text);

int spd_cancel(void *connection);

int spd_set_voice_rate(void *connection, signed int rate);

void spd_close(void *connection);

typedef unsigned int UINT;
typedef unsigned int DWORD;
typedef const char * LPCSTR;
typedef wchar_t * LPWSTR;

int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar);

void Tolk_TrySAPI(bool trySAPI);
void Tolk_Load();
bool Tolk_Output(const char *s, bool interrupt);
void Tolk_Silence();

]]

local lib

local kernel32

local speech

if ffi.os == "Linux" then
  lib = ffi.load("speechd")
  speech = lib.spd_open("love2d", "love2d", "love2d", lib.SPD_MODE_SINGLE)
  lib.spd_set_voice_rate(speech, 100)
elseif ffi.os == "Windows" then
  kernel32 = ffi.load("kernel32")
  lib = ffi.load("Tolk")
  lib.Tolk_TrySAPI(true)
  lib.Tolk_Load()
end

local CP_UTF8 = 65001

function to_utf16(s)
  local needed = kernel32.MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0)
  local buf = ffi.new("wchar_t[?]", needed)
  local written = kernel32.MultiByteToWideChar(CP_UTF8, 0, s, -1, buf, needed)
  return ffi.string(buf, written*2)
end

local M = {}

function M.say(text, interrupt)
  if interrupt == nil then
    interrupt = true
  end
  if ffi.os == "Linux" then
    if interrupt then
      lib.spd_cancel(speech)
    end
    lib.spd_say(speech, lib.SPD_IMPORTANT, text)
  elseif ffi.os == "Windows" then
    lib.Tolk_Output(to_utf16(text), interrupt)
  end
end

function M.stop()
  if ffi.os == "Linux" then
    lib.spd_cancel(speech)
  elseif ffi.os == "Windows" then
    lib.Tolk_Silence()
  end
end

return M

Thumbs up

2019-04-11 03:46:37

For future reference. To determine whether a dll is 32 or 64 bit you have a couple options. Either use file (the unix utility) on windows with cygwin or mingw, dependency walker or write a script to decipher the info.

File is simple as
file bla.dll
bla.dll: PE32 executable (DLL) (GUI) Intel 80386, for MS Windows

With dependency walker, control+o, locate file, check the CPU tab.

The writing a script option isn't as straight forward, have a look at the PE file format. You're looking for machine in the COFF header. This shouldn't be necessary, as shown quite a few other options exist already. Could be a beginner exercise though.

For OS X speech, I'd personally try getting LuaCocoa to interface with NsSpeechSynthasizer. It's apparently a new version of LuaObjCBridge, for python people a lua pyobjc like thing. While it certainly looks promicing, I've never tried and unfortunately don't have the time to throw something together at the moment. Another last ditch option is to simply os.execute "say" with parameters but that should be avoided at all costs.

Thumbs up

2019-04-11 04:56:45 (edited by Ethin 2019-04-11 06:29:25)

You can also open the file in notepad/whatever text editor (raw text editor) and look for either PE  l or PE  d. If you find PE  l, you've got a 32-bit DLL; if is PE  d, you've got 64-bit. At least, that's according to a stack overflow post.
I'm suffering a new problem now. I have a menu state (I'm using hump.gamestate). The :enter function sets up audio sources. For some reason, the background music is playing only about a half-second and then immediately rewinding back to the beginning. I know that that's not the end, since the file is over 7 minutes long. This happens with both streaming and static sources. This however does not happen with any other source though, other than the BGM.
Edit: this actually does happen. I removed the BGM to est my theory and it happens as soon as I go to play a new source. And I have no idea why its happening either.

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.

Thumbs up

2019-04-12 00:38:35

@10 Thanks for the pointers. I'd run file on the DLL. I think the bit that threw me off was "PE32". Part of the file output seemed to indicate that it was 64-bit. When I ran it on other DLLs in the directory, it became apparent that it wasn't.

And FWIW, this is now supposedly fixed, and the master builds are once again 32-bit. I haven't confirmed that, but the GitHub issue tracking it was closed.

Thumbs up