Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Microphone input
#1
I think my mic is broken or something so can someone test this please...

Microphone.h 

Code: (Select All)
#ifndef QBLIVE_AUDIO_H
#define QBLIVE_AUDIO_H

#include <windows.h>
#include <mmsystem.h>
#include <shellapi.h>
#include <vector>

#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "shell32.lib")

#define SAMPLE_RATE 44100
#define CHUNK_SIZE 4096

static HWAVEIN hWaveIn = NULL;
static HWAVEOUT hWaveOut = NULL;
static WAVEHDR waveHdrIn;
static short captureBuffer[CHUNK_SIZE];
static std::vector<short> recordedData;
static bool isRecording = false;

// Driver Callback: Background thread catches audio chunks as they arrive
void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
    if (uMsg == WIM_DATA && isRecording) {
        WAVEHDR* pHdr = (WAVEHDR*)dwParam1;
        short* raw = (short*)pHdr->lpData;
        // Efficiently append raw 16-bit samples to the storage vector
        recordedData.insert(recordedData.end(), raw, raw + (pHdr->dwBytesRecorded / 2));
        // Re-queue the buffer to keep recording without gaps
        waveInAddBuffer(hwi, pHdr, sizeof(WAVEHDR));
    }
}

extern "C" {
    __declspec(dllexport) int InitAudio() {
        // CD Quality: Mono, 44100Hz, 16-bit PCM
        WAVEFORMATEX wfx = { WAVE_FORMAT_PCM, 1, SAMPLE_RATE, SAMPLE_RATE * 2, 2, 16, 0 };
       
        // Open Microphone
        MMRESULT res = waveInOpen(&hWaveIn, WAVE_MAPPER, &wfx, (DWORD_PTR)waveInProc, 0, CALLBACK_FUNCTION);
        if (res != MMSYSERR_NOERROR) return (int)res;

        waveHdrIn.lpData = (LPSTR)captureBuffer;
        waveHdrIn.dwBufferLength = CHUNK_SIZE * 2;
        waveHdrIn.dwFlags = 0;
        waveInPrepareHeader(hWaveIn, &waveHdrIn, sizeof(WAVEHDR));
       
        // Open Speakers
        if (waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR) return -99;
       
        return 0;
    }

    __declspec(dllexport) void StartRecord() {
        recordedData.clear();
        isRecording = true;
        waveInAddBuffer(hWaveIn, &waveHdrIn, sizeof(WAVEHDR));
        waveInStart(hWaveIn);
    }

    __declspec(dllexport) void StopRecord() {
        isRecording = false;
        waveInStop(hWaveIn);
        waveInReset(hWaveIn);
    }

    __declspec(dllexport) int GetRecordedSize() {
        return (int)recordedData.size();
    }

    __declspec(dllexport) void PlayRecording() {
        if (recordedData.empty()) return;
        static WAVEHDR playHdr; // Static ensures memory persists during playback
        playHdr.lpData = (LPSTR)recordedData.data();
        playHdr.dwBufferLength = (DWORD)recordedData.size() * 2;
        playHdr.dwFlags = 0;
        waveOutPrepareHeader(hWaveOut, &playHdr, sizeof(WAVEHDR));
        waveOutWrite(hWaveOut, &playHdr, sizeof(WAVEHDR));
    }

    __declspec(dllexport) void OpenMicSettings() {
        ShellExecuteA(NULL, "open", "ms-settings:privacy-microphone", NULL, NULL, SW_SHOWNORMAL);
    }

    __declspec(dllexport) void ShutdownAudio() {
        if (hWaveIn) { waveInReset(hWaveIn); waveInClose(hWaveIn); }
        if (hWaveOut) { waveOutReset(hWaveOut); waveOutClose(hWaveOut); }
    }

        // Converts 16-bit samples to 32-bit floats for QB64 _SNDRAW
    // buffer = the QB64 float array, offset = starting sample, count = samples to get
    __declspec(dllexport) void Audio_Get_SndRaw(float* buffer, int offset, int count) {
        if (recordedData.empty() || offset < 0) return;
       
        for (int i = 0; i < count; i++) {
            int index = offset + i;
            if (index < (int)recordedData.size()) {
                // Convert signed 16-bit (-32768 to 32767) to float (-1.0 to 1.0)
                buffer[i] = (float)recordedData[index] / 32768.0f;
            } else {
                buffer[i] = 0.0f; // Fill remaining buffer with silence if out of range
            }
        }
    }

}
#endif

ANd the QB64 stuff 

Code: (Select All)
' Finalized QBLive Audio Studio 2025
DECLARE LIBRARY "Microphone"
  FUNCTION InitAudio& ()
  SUB StartRecord ()
  SUB StopRecord ()
  FUNCTION GetRecordedSize& ()
  SUB PlayRecording ()
  SUB OpenMicSettings ()
  SUB ShutdownAudio ()
  SUB Audio_Get_SndRaw (buffer AS SINGLE, BYVAL offset AS LONG, BYVAL count AS LONG)

END DECLARE

SCREEN _NEWIMAGE(800, 600, 32)
_TITLE "QBLive Audio Recorder 2025"

' 1. Check Permissions
res& = InitAudio
IF res& <> 0 THEN
  PRINT "--- AUDIO INITIALIZATION ERROR ---"
  PRINT "Result Code:"; res&
  PRINT "Hardware not found or Privacy Permissions denied."
  PRINT
  INPUT "Open Windows Microphone Settings? (Y/N) ", c$
  IF UCASE$(c$) = "Y" THEN OpenMicSettings
  END
END IF

isRecording = 0
PRINT "Ready. Press SPACE to Record."

DO
  k$ = INKEY$
  IF k$ = " " THEN
    IF isRecording = 0 THEN
      StartRecord
      isRecording = 1
    ELSE
      StopRecord
      isRecording = 0
      CLS
      PRINT "Playing back"; GetRecordedSize; "samples..."
      'PlayRecording ''// This maybe the error

      samples& = GetRecordedSize

      IF samples& > 0 THEN
        PRINT "Playing back via _SNDRAW..."

        ' We process in chunks of 4096 (matching your C++ CHUNK_SIZE)
        chunkSize& = 4096
        REDIM tempBuffer(chunkSize& - 1) AS SINGLE

        FOR currentOffset& = 0 TO samples& STEP chunkSize&
          ' 1. Fill our QB64 float buffer from the C++ recordedData vector
          Audio_Get_SndRaw tempBuffer(0), currentOffset&, chunkSize&

          ' 2. Call our standalone sub to handle the actual playback
          PlayFloatBuffer tempBuffer(), chunkSize&
        NEXT currentOffset&

        PRINT "Playback finished."
      END IF

      PRINT "Press SPACE to record again."
    END IF
    _DELAY .3 ' Toggle debounce
  END IF

  IF isRecording THEN
    LOCATE 1, 1: PRINT "RECORDING... ["; GetRecordedSize; "samples]"
  END IF
  _LIMIT 60
LOOP UNTIL _EXIT

ShutdownAudio
SYSTEM


SUB PlayFloatBuffer (floatArray() AS SINGLE, count AS LONG)
  ' Designed for 44100Hz Mono Audio
  IF count <= 0 THEN EXIT SUB

  FOR i& = 0 TO count - 1
    ' 1. Send the sample to _SNDRAW (mono automatically goes to both speakers)
    _SNDRAW floatArray(i&)

    ' 2. Check the sound pipe length.
    ' If we queue too much data (> 0.2 seconds), we wait.
    ' If we don't wait, QB64 will eat up all your RAM trying to store the samples.
    IF i& MOD 100 = 0 THEN ' Check every 100 samples to save CPU
      DO WHILE _SNDRAWLEN > 0.2
        _LIMIT 100 ' Give the CPU a rest while the sound card works
      LOOP
    END IF
  NEXT i&
END SUB

@Petr 90% there i reckon...needs a better brain!

Unseeen
Reply


Messages In This Thread
Microphone input - by Unseen Machine - 12-25-2025, 02:27 AM
RE: Microphone input - by Petr - 12-25-2025, 10:31 AM
RE: Microphone input - by Kernelpanic - 12-25-2025, 02:13 PM
RE: Microphone input - by Petr - 12-25-2025, 02:47 PM
RE: Microphone input - by Kernelpanic - 12-25-2025, 04:35 PM
RE: Microphone input - by Unseen Machine - 12-25-2025, 06:54 PM
RE: Microphone input - by Kernelpanic - 12-25-2025, 07:25 PM
RE: Microphone input - by Petr - 12-25-2025, 07:25 PM
RE: Microphone input - by Petr - 12-25-2025, 07:42 PM
RE: Microphone input - by Kernelpanic - 12-25-2025, 09:10 PM
RE: Microphone input - by Unseen Machine - 12-25-2025, 07:49 PM
RE: Microphone input - by Petr - 12-25-2025, 09:34 PM
RE: Microphone input - by Kernelpanic - 12-25-2025, 11:03 PM
RE: Microphone input - by Petr - 12-25-2025, 11:31 PM
RE: Microphone input - by Kernelpanic - 12-25-2025, 11:50 PM

Possibly Related Threads…
Thread Author Replies Views Last Post
  Let's take this input for a spin doppler 0 620 05-07-2022, 02:57 PM
Last Post: doppler

Forum Jump:


Users browsing this thread: