Playing audio in Windows = Core Audio API?

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

:love: Thanks XOXOS! Above & beyond the call of duty. :love:

Now let's see if I can write some microcode worthy of all your support...

Post

it does appear that graphics does have an update:

under Get Started with Win32 and C++
09/10/2021
https://docs.microsoft.com/en-us/window ... or-windows

section 3: Overview of the Windows Graphics Architecture
02/08/2021
https://docs.microsoft.com/en-us/window ... chitecture
Graphics Device Interface (GDI) is the original graphics interface for Windows. ...
GDI+ was introduced in Windows XP as a successor to GDI. ...
Direct3D supports 3-D graphics.
Direct2D is a modern API for 2-D graphics, the successor to both GDI and GDI+.
DirectWrite is a text layout and rasterization engine. ...
Direct2D and DirectWrite were introduced in Windows 7. ...

While both GDI and GDI+ continue to be supported in Windows, Direct2D and DirectWrite are recommended for new programs.
*edit* i'm obliged to add, the "introduction to direct2d" in this link is useless as it requires you to restructure all of your windows code ("sorry no link for completed document"). i've found a separate document set addressing "quickstart for direct2d" but this is equally dysfunctional (eg. there's a sample code of direct2d clockface using transforms for the hands, 51 error reports and document pulled). atm going thru youtube videos. there are some real slow speakers/organisers who seem to have found this subject of interest.
you come and go, you come and go. amitabha neither a follower nor a leader be tagore "where roads are made i lose my way" where there is certainty, consideration is absent.

Post

here's what i nabbed/parsed from here - much cleaner, d2d stuff in a separate document. i don't know if it's the best use but it's the one i could get to work.
https://www.youtube.com/watch?v=ng9Ho9qcVII&t=1212s

.cpp file is simpler, starting there. add under includes:

Code: Select all

#include <d2d1.h>
#pragma comment(lib, "d2d1.lib")

#include "direct2d.h"
graphics* gfx;
put this at the end of wWinMain:
delete gfx;

add WM_CREATE:

Code: Select all

    case WM_CREATE:
        {
            gfx = new graphics();
            if (!gfx->init(hWnd)) {
                delete gfx;
                return -1;
            };
        }
    break;
and here's WM_PAINT:

Code: Select all

        PAINTSTRUCT ps;
        BeginPaint(hWnd, &ps);

        gfx->begindraw();
        gfx->clear(.5f,.5f,0);
        gfx->circle(100,100,25,1.f,.5f,0.f,1.f);
        gfx->fillcircle(200, 100, 25, 1.f, .5f, 0.f, 1.f);
        gfx->triangle(600, 250, 700,100, 800,400, 1.f, 0.f, 0.f, 1.f);
        gfx->enddraw();

        EndPaint(hWnd, &ps);
and here's the direct2d.h i created:

Code: Select all

class graphics
{
	ID2D1Factory* factory;
	ID2D1HwndRenderTarget* rendertarget;
	ID2D1SolidColorBrush* brush;
	ID2D1PathGeometry* pathgeometry;
	ID2D1GeometrySink* gsink;

public:
	graphics();
	~graphics();
	bool init(HWND windowhandle);

	void begindraw() {rendertarget->BeginDraw();}
	void enddraw() {rendertarget->EndDraw();}

	void clear(float r, float g, float b);
	void circle(float x, float y, float radius, float r, float g, float b, float a);
	void fillcircle(float x, float y, float radius, float r, float g, float b, float a);
	void rectangle(float x, float y, float x0, float y0, float width, float r, float g, float b, float a);
	void fillrectangle(float x, float y, float x0, float y0, float r, float g, float b, float a);
	void line(float x, float y, float x0, float y0, float width, float r, float g, float b, float a);
	void triangle(float x, float y, float x0, float y0, float x1, float y1, float r, float g, float b, float a);
};

graphics::graphics() {
	factory = NULL;
	rendertarget = NULL;
	brush = NULL;
	pathgeometry = NULL;
	gsink = NULL;
}

graphics::~graphics() {
	if(factory) factory->Release();
	if (rendertarget) rendertarget->Release();
	if (brush) brush->Release();
	if(pathgeometry) pathgeometry->Release();
	if (gsink) gsink->Release();
}

bool::graphics::init(HWND windowhandle) {
	HRESULT result = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory);
	if (result != S_OK) return false;

	RECT rect;
	GetClientRect(windowhandle, &rect);

	result = factory->CreateHwndRenderTarget(
		D2D1::RenderTargetProperties(),
		D2D1::HwndRenderTargetProperties(windowhandle, D2D1::SizeU(rect.right, rect.bottom)),
		&rendertarget);
	if (result != S_OK) return false;

	rendertarget->CreateSolidColorBrush(D2D1::ColorF(0,0,0,1), &brush);
	factory->CreatePathGeometry(&pathgeometry);

	return true;
}


void graphics::clear(float r, float g, float b) {
	rendertarget->Clear(D2D1::ColorF(r, g, b));
}

void graphics::circle(float x, float y, float radius, float r, float g, float b, float a) {
	brush->SetColor(D2D1::ColorF(r, g, b, a));
	rendertarget->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(x, y), radius, radius), brush, 3.f);	
}

void graphics::fillcircle(float x, float y, float radius, float r, float g, float b, float a) {
	brush->SetColor(D2D1::ColorF(r, g, b, a));
	rendertarget->FillEllipse(D2D1::Ellipse(D2D1::Point2F(x, y), radius, radius), brush);
}

void graphics::rectangle(float x, float y, float x0, float y0, float width, float r, float g, float b, float a) {
	brush->SetColor(D2D1::ColorF(r, g, b, a));
	rendertarget->DrawRectangle(D2D1::RectF(x, y, x0, y0), brush, width);
}

void graphics::fillrectangle(float x, float y, float x0, float y0, float r, float g, float b, float a) {
	brush->SetColor(D2D1::ColorF(r, g, b, a));
	rendertarget->FillRectangle(D2D1::RectF(x, y, x0, y0), brush);
}

void graphics::line(float x, float y, float x0, float y0, float width, float r, float g, float b, float a) {
	brush->SetColor(D2D1::ColorF(r, g, b, a));
	rendertarget->DrawLine(D2D1::Point2F(x, y), D2D1::Point2F(x0, y0), brush, width);
}

void graphics::triangle(float x, float y, float x0, float y0, float x1, float y1, float r, float g, float b, float a) {
	brush->SetColor(D2D1::ColorF(r, g, b, a));

	rendertarget->SetTransform(D2D1::Matrix3x2F::Rotation(-15.f, D2D1::Point2F(468.0f, 331.5f)));

	HRESULT result = factory->CreatePathGeometry(&pathgeometry);
	result = pathgeometry->Open(&gsink);
	gsink->BeginFigure(D2D1::Point2F(x, y), D2D1_FIGURE_BEGIN_FILLED);
	gsink->AddLine(D2D1::Point2F(x0, y0));
	gsink->AddLine(D2D1::Point2F(x1, y1));
	gsink->EndFigure(D2D1_FIGURE_END_CLOSED);
	gsink->Close();

	rendertarget->FillGeometry(pathgeometry, brush);


	rendertarget->SetTransform(D2D1::Matrix3x2F::Identity());
}
the triangle function is a quick do of their "path geometry" idea which can draw complex curves, the example here has a test rotation on it.

i don't know if this is the ace way to do it because it's wrapping all the functions. haven't had a go at unwrapping yet to make it simpler but i realised what i had so far is immensely more straightforward than what i could find presented so posting. testing the stability of coding d2d can be done by resizing the window, some stuff will run but get bad then. if it resizes, it floats imo.

an essential concept update is the idea of Device Independent Pixels.. the default is that you access virtual pixels that are resized, you can select for pixel rendering accuracy but it seems better not to. the old GetCursorPos seems to return a position that aligns with rendering coordinates (i saw some conversion API somewhere but can't relocate the clean example i saw) so something to be aware of. there's also a strokestyle thingo for setting end and corner styles. there's a lot of stupid looking code out there.
you come and go, you come and go. amitabha neither a follower nor a leader be tagore "where roads are made i lose my way" where there is certainty, consideration is absent.

Post

Quick and dirty saw wave using RtAudio:

Code: Select all

#include "RtAudio.h"

double freq=100.0;
unsigned int bufferFrames=512, sampleRate=44100;
signed short out=0;
signed short step=(unsigned short)(65535.0*freq/(double)sampleRate);

int saw(void *outputBuffer, void *, unsigned int nBufferFrames, double , RtAudioStreamStatus status, void *){
    signed short* buffer=(signed short*)(outputBuffer);
    for(unsigned int i=0; i<nBufferFrames; i++){
        out+=step;
        *buffer++ = out;
    }
    return 0;
}

int main(){
    RtAudio dac;
    RtAudio::StreamParameters oParams;
    oParams.deviceId = 0;
    oParams.nChannels = 1;
    oParams.firstChannel = 0;
    dac.openStream(&oParams, NULL, RTAUDIO_SINT16, sampleRate, &bufferFrames, &saw, NULL, NULL, NULL);
    dac.startStream();
    char c;
    std::cin.get(c);
    dac.stopStream();
    dac.closeStream();
    return 0;
}
However first you'll need to build RtAudio to be able to use this, it's explained in a text file contained in the download. I used the CMake method to build it on Windows. There's some examples included in the download, one of them is a more elaborate "playsaw.cpp" file which handles interleaving/other data types/error handling/...

Return to “DSP and Plugin Development”