Existe um equivalente Windows para o Linux “aplay” que aceitará um fluxo de bits e saída de áudio?

2

Eu estava assistindo um vídeo do Computerphile sobre code-golf e chiptunes e estava interessado em executar o código de exemplo fornecido , mas depende do aplay , um utilitário do Linux para o driver da placa de som ALSA, e gostaria de executar isso no Windows 7. Existe um programa ou utilitário equivalente no Windows 7+ (de preferência, mas não necessariamente fornecido pelo sistema operacional) que tomará um fluxo de bytes e o converterá em um fluxo de áudio?

    
por Ken Bellows 11.01.2016 / 17:35

4 respostas

0

same:)

Descobri que você pode usar o ffmpeg para convertê-lo

ffmpeg -f u8 -i music.raw music.wav

Depois use o que quiser para jogá-lo

Agora, tentei canalizá-lo diretamente (vlc permite entrada em stdin, mas ele não lê dados brutos, pelo menos não sem argumentos, não sei como dar lol)

music.exe | ffmpeg ... -i pipe:1 | vlc.exe -

mas o ffmpeg disse que o pipe não tinha espaço suficiente (eu tentei o pipe: 0 também porque eu não tinha 100% de certeza de qual seria o stdin no windows ...)

então eu acabei redirecionando o music.exe para um arquivo music.raw por um pequeno período de tempo ( music.exe > music.raw ), então eu poderia usar isso para canalizar direto do ffmpeg para o vlc

ffmpeg.exe -f u8 -i music.raw -f wav pipe:1 | vlc.exe -
    
por 11.01.2016 / 22:27
3

Eu assisti exatamente o mesmo vídeo e fiquei muito desapontado por não conseguir encontrar um programa para Windows que se comportasse como um jogo neste exemplo.

No final, eu mesmo escrevi um usando C ++ e OpenAL . Eu vou postar o código abaixo. Você terá que vincular à biblioteca OpenAL para criar o executável. A biblioteca faz parte do OpenAL Core SDK, que você pode baixar do site deles.

Se você quer apenas o executável, você pode baixá-lo aqui . Procure por yalpa.exe .

Sintaxe

Digamos que você use meu executável yalpa.exe . Então você pode processar seus dados de áudio brutos, canalizando-os para yalpa:

a.exe | yalpa.exe

Como alternativa, você pode primeiro gravar os dados de áudio em um arquivo e passar esse arquivo para a stdin de yalpa:

yalpa.exe < my_audio.raw

Nota: yalpa funciona em cmd, mas não no PowerShell. Pipes parecem ser tratados de forma diferente lá (consulte esta questão SO relacionada ).

O código:

Isenção de responsabilidade: Não posso garantir que este código seja 100% livre de erros, mas testei-o em duas máquinas diferentes com o Windows 7 e o Windows 10, respectivamente. Ele foi compilado e vinculado usando o compilador do Visual Studio 2013. Também consegui compilá-lo usando o g ++ no Cygwin, mas o OpenAL falhou durante a execução devido a problemas com o pulseaudio.

Sinta-se à vontade para editar e usar meu código.

#include <iostream>
#include <cstdio>
#include <cstdint>
#include <thread>
#include <chrono>

#if defined _WIN32
#include <al.h>
#include <alc.h>
#include <io.h>
#include <fcntl.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#endif

#if 0 || defined _DEBUG
#define AL_CHECK_ERROR(msg) (checkALError(msg))
#else
#define AL_CHECK_ERROR(msg)
#endif

const uint8_t numBuf = 3;
const ALsizei bufSize = 1000;
const ALenum format = AL_FORMAT_MONO8;
const ALsizei freq = 8000;
char readBuf[bufSize]; 

void checkALError(const char * msg)
{
    while (ALuint err = alGetError() != AL_NO_ERROR)
        std::cerr << "Caught AL Error at " << msg << ": " << err << "\n";
}

ALsizei fillBufferFromStdin(ALuint buf)
{
    // read
    const ALsizei bytesRead = (ALsizei) fread(readBuf, sizeof(uint8_t), bufSize, stdin);
    // copy to OpenAL buffer
    alBufferData(buf, format, (void *) readBuf, bytesRead, freq);
    AL_CHECK_ERROR("buffer data");
    return bytesRead;
}

void updateBuffers(ALuint src, ALuint bufs[numBuf])
{
    ALint srcState;
    do
    {
        // wait until a buffer is free
        ALint val = 0;
        do 
        {
            alGetSourcei(src, AL_BUFFERS_PROCESSED, &val);
            AL_CHECK_ERROR("get num processed");
            if (val > 0) break;
            // sleep for a quarter of the duration a buffer plays
            std::this_thread::sleep_for(std::chrono::milliseconds((bufSize / freq) * 1000 / 4));
        } while (true);
        while (val--)
        {
            // remove oldest buffer from queue and get its id
            ALuint buf;
            alSourceUnqueueBuffers(src, 1, &buf);
            AL_CHECK_ERROR("unqueue buffer");
            // fill buffer
            const ALsizei bytesRead = fillBufferFromStdin(buf);
            // add buffer to queue
            alSourceQueueBuffers(src, 1, &buf);
            AL_CHECK_ERROR("queue buffer");
            // if end of stdin was reached, return
            if (bytesRead < bufSize) return;
        }
        // check if source is still playing
        alGetSourcei(src, AL_SOURCE_STATE, &srcState);
    } while (AL_PLAYING == srcState);
}

int main(int argc, char * argv[])
{
    std::cout << "OpenAL test project\n";
    // set stdin to binary mode
#ifdef _WIN32
    _setmode(_fileno(stdin), _O_BINARY);
#else
    freopen(nullptr, "rb", stdin);
#endif

    // initialization: open default device
    ALCdevice * dev = alcOpenDevice(nullptr);
    // reset error state
    AL_CHECK_ERROR("open device");
    // create a context
    ALCcontext * context = alcCreateContext(dev, nullptr);
    AL_CHECK_ERROR("create context");
    alcMakeContextCurrent(context);
    AL_CHECK_ERROR("activate context");
    // create buffers for audio streaming
    ALuint bufs[numBuf];
    alGenBuffers(numBuf, bufs);
    AL_CHECK_ERROR("create buffer");
    // create source to play buffer
    ALuint src;
    alGenSources(1, &src);
    AL_CHECK_ERROR("create source");

    // initially fill buffers
    for (uint8_t i = 0; i < numBuf; ++i) fillBufferFromStdin(bufs[i]);
    alSourceQueueBuffers(src, numBuf, bufs);
    AL_CHECK_ERROR("queue buffer");
    // play source
    alSourcePlay(src);
    AL_CHECK_ERROR("play");
    // fill buffers in loop
    updateBuffers(src, bufs);
    // when stream is read completely, wait until source stops playing
    ALint srcState;
    do
    {
        alGetSourcei(src, AL_SOURCE_STATE, &srcState);
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    } while (AL_PLAYING == srcState);


    // delete source
    alDeleteSources(1, &src);
    AL_CHECK_ERROR("delete source");
    // delete buffers
    alDeleteBuffers(numBuf, bufs);
    AL_CHECK_ERROR("delete buffer");
    // destroy context
    alcDestroyContext(context);
    AL_CHECK_ERROR("destroy context");
    // close device
    alcCloseDevice(dev);
    AL_CHECK_ERROR("close device");

    std::cout << "Exiting\n";
    return 0;
}
    
por 15.01.2016 / 17:25
1

Usando a vlc e alguns argumentos de linha de comando copiados e colados da Internet, você pode recriar a funcionalidade do jogo no Windows.

audio.exe | vlc --demux=rawaud --rawaud-channels 2 --rawaud-samplerate 8000 -

O crédito deve ir para este post e à resposta do FreeER.

    
por 14.10.2018 / 23:12
0

Para a posteridade: parece que não há realmente uma boa solução, mas uma outra solução aproximada que encontrei foi usar SoX com as seguintes opções para gerar um arquivo .wav:

./a.exe | sox -t raw -b 16 -e signed -r 8000 - test.wav

Isso cria um arquivo muito grande muito rapidamente, por isso não deixe que ele seja executado por muito tempo. Cerca de 10 segundos na minha máquina (processador Intel i7 3.4GHz) geraram cerca de 2 horas de áudio (~ 125KB).

    
por 11.01.2016 / 22:43