Bir bit akımını kabul eden ve çıkan sesi kabul eden Linux “aplay” değerine eşdeğer bir Windows var mı?


3

Code golf ve chiptunes hakkında bir Computerphile videosu izliyordum ve verilen örnek kodu çalıştırmak istiyordum aplay, ancak ALSA ses kartı sürücüsü için bir Linux yardımcı programına dayanıyordu ve bunu Windows 7'de çalıştırmak istiyorum. bir bayt akışını alıp bir ses akışına dönüştürecek olan Windows 7+ üzerinde (tercihen ancak mutlaka işletim sistemi tarafından sağlanmayan) eşdeğer bir program veya yardımcı program?

Yanıtlar:


0

aynı :)

Dönüştürmek için ffmpeg kullanabileceğini öğrendim

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

O zaman ne istersen onu kullan

Şimdi direkt olarak pipolamayı denedim.

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

ama ffmpeg borunun yeterli boşluğu olmadığını söyledi (boruyu denedim: 0 da, pencerelerde stdin için% 100 olduğundan emin değildim ...)

bu yüzden, music.exe dosyasını bir süredir music.raw dosyasına yönlendirerek bittim ( music.exe > music.raw) sonra bunu doğrudan ffmpeg'den vlc'ye yönlendirmek için kullanabilirim

ffmpeg.exe -f u8 -i music.raw -f wav pipe:1 | vlc.exe -

Bu herhangi bir cevap kadar iyi, bu yüzden onu işaretleyeceğim. Bence asıl cevap, pencerelerde doğrudan iyi bir boru çözümü olmadığı
Ken Bellows

Ben sizin bu yorum yapmak isterdim ama 50 temsilcisi :) yok unix.stackexchange.com/questions/205107/... komutu biraz daha uzun olabilir iken bu yüzden bir google arama ile yukarıda bulundu ./a | aplay, teşekkür teorik olarak dosyayı kaydetmek zorunda kalmadan bunu yapabilirdi. Komutu makefile / batch dosyasına vs. ekleyebilirsin.
FreeER

SoX'dan play.exe kullanırken karşılaştığım asıl sorun, Windows ses sürücüleri ile etkileşime girme zorluğudur. Belki de sadece SoX hakkında yeterince bilgim yok ama henüz play.exe'nin nasıl bir hata yapmadan çalışacağını henüz çözemedim
Ken Bellows

hm, ben sox için indirme aslında play.exe yoktu ama ben sadece bir dosya yerine "-t -waveaudio default" bir çıktı belirtebilirsiniz bulundu. btw, ilgileniyorsanız hepsini dropbox'a attım: dropbox.com/sh/ibb924waxkqga04/AAAa3yxp_lf7_awM2eY30bPqa?dl=0
FreeER

1
Sadece bir boru numarası belirtmezseniz ffmpeg ile çalıştığını öğrendim. Sadece yazın a.exe | ffmpeg.exe -ar 8000 -f u8 -i pipe: -f wav pipe: | vlc.exe -ve gitmeniz iyi olur. Seçenek -ar, örnekleme hızını 8000 Hz olarak ayarlar. Varsayılan olarak ffmpeg 44100 Hz kullanır.
maddin45,

3

Aynı videoyu izledim ve bu örnekte aplay gibi davranan pencereler için bir program bulamadığım için çok hayal kırıklığına uğradım.

Sonunda kendimi C ++ ve OpenAL kullanarak yazdım . Aşağıdaki kodu göndereceğim. Yürütülebilir dosyayı oluşturmak için OpenAL kitaplığına bağlanmanız gerekecektir. Kütüphane, web sitelerinden indirebileceğiniz OpenAL Core SDK'nin bir parçasıdır.

Sadece yürütülebilir istiyorsanız, bunu indirebilirsiniz burada . İçin bak yalpa.exe.

Sözdizimi

Benim çalıştırılabilirimi kullandığınızı varsayalım yalpa.exe. Ardından, ham ses verilerinizi yalpa'ya bağlayarak işleyebilirsiniz:

a.exe | yalpa.exe

Alternatif olarak, önce ses verilerini bir dosyaya yazıp o dosyayı yalpa'nın stdinine aktarabilirsiniz:

yalpa.exe < my_audio.raw

Not: yalpa cmd olarak çalışır, ancak PowerShell'de çalışmaz. Borular orada farklı şekilde ele alınmış gibi görünüyor ( ilgili SO sorusuna bakınız ).

Kod:

Feragatname: Bu kodun% 100 hatasız olduğunu garanti edemem, ancak sırasıyla Windows 7 ve Windows 10 ile iki farklı makinede test ettim. Visual Studio 2013 derleyicisi kullanılarak derlendi ve bağlandı. Ayrıca Cygwin'de g ++ kullanarak derleyebildim, ancak OpenAL pulseaudio'daki problemler nedeniyle çalışma zamanında başarısız oldu.

Kodumu düzenlemek ve kullanmaktan çekinmeyin.

#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;
}

1

İnternetten kopyaladığım vlc ve bazı komut satırı argümanlarını kullanarak aplay'ün Windows'taki işlevselliğini yeniden oluşturabilirsiniz.

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

Kredi bu yazıya ve FreeER'in cevabına gitmelidir.


bit akımı kaynak parametresi nerede?
nicolay.anykienko

0

Posterity için: gerçekten iyi bir çözüm yok gibi gözüküyor, fakat bulduğum yaklaşık bir tane daha .wav dosyası oluşturmak için SoX'u aşağıdaki seçeneklerle kullanmaktı:

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

Bu çok hızlı bir şekilde çok büyük bir dosya oluşturur, bu yüzden çok uzun süre çalışmasına izin vermeyin. Makinemde yaklaşık 10 saniye (Intel i7 3.4 GHz işlemci) yaklaşık 2 saat ses üretti (~ 125KB).


Sox'u bilmeden , çıktıyı bir bayt ile sınırlandırmak için çıktı vermesini ve stdoutsonra bunu yönlendirmesini söyleyebilirsiniz head -c <bytes>. samples/second × bytes/channel/sample × channels × seconds = bytes. Başlık nedeniyle birkaç örneği kaybedeceksiniz, ancak hızlı ve kirli bir yöntem. Aksi halde, soxbir girişi kırpmanıza izin verecek bir komutu vardır: sox <options> - test.wav trim 0 60anlamı 0 saniye atlayacak ve girişten 60 saniye alacaktır.
sleblanc
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.