Skip to content

Commit

Permalink
v0.60. Tao MS3 support
Browse files Browse the repository at this point in the history
  • Loading branch information
arnaud-carre committed Aug 22, 2023
1 parent cd57cf2 commit f2af36f
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 50 deletions.
60 changes: 46 additions & 14 deletions AtariAudio/SteDac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ void SteDac::Reset(uint32_t hostReplayRate)
m_microwireShift = 0;
m_microwireData = 0;
m_masterVolume = 64;
m_currentDacLevel = 0;
m_50Acc = 0;
m_50to25 = false;
}

void SteDac::FetchSamplePtr()
Expand Down Expand Up @@ -47,6 +50,13 @@ void SteDac::Write8(int ad, uint8_t data)
case 0x7:
case 0xd:
data &= 0xfe;
case 0x21:
if ((data & 3) != (m_regs[0x21]&3))
{
m_50Acc = 0;
m_50to25 = false;
}
break;
default:
break;
}
Expand Down Expand Up @@ -125,23 +135,44 @@ int8_t SteDac::FetchSample(const int8_t* atariRam, uint32_t ramSize, uint32_t at

int16_t SteDac::ComputeNextSample(const int8_t* atariRam, uint32_t ramSize, Mk68901& mfp)
{
int16_t level = 0;
// supports tricky Tao "MS3" driver. Seems to be a 3 or 4 voices synth, without need of mixing code!
// the 4 voices are just output in 4 consecutive bytes. Everything is playing at 50Khz, stereo
// On real hardware with analog filters & friends, it "sounds" like if you mixed 4 voices at 25Khz
//
// ComputeNextSample is called at host rate
// but the while loop is running at DAC speed. In 50khz mode, 2 samples are accumulated before
// output. So you get a mixed stream at 25Khz. None of original atari samples are missed, and
// Tao MS3 songs are playing ok!
// Please note it also works perfectly with Quartet STE code, that is mixing into a 2 bytes 50Khz buffer!! :)
static const uint32_t sDacFreq[4] = { kSTE_DAC_Frq / 8 , kSTE_DAC_Frq / 4 , kSTE_DAC_Frq / 2 , kSTE_DAC_Frq / 1 };
if (m_regs[1] & 1)
{
const bool mono = (m_regs[0x21] & 0x80);
level = FetchSample(atariRam, ramSize, m_samplePtr) * m_masterVolume; // 14bits
if (!mono)
{
int16_t levelR = FetchSample(atariRam, ramSize, m_samplePtr + 1) * m_masterVolume;
level += levelR; // 15bits
}

static const uint32_t sDacFreq[4] = { kSTE_DAC_Frq/8 , kSTE_DAC_Frq/4 , kSTE_DAC_Frq/2 , kSTE_DAC_Frq/1};
m_innerClock += sDacFreq[m_regs[0x21] & 3];
// most of the time this while will never loop
const bool stereo = (0 == (m_regs[0x21] & 0x80));
const bool b50k = (3 == (m_regs[0x21]&3));

while (m_innerClock >= m_hostReplayRate)
{
m_samplePtr += mono ? 1 : 2;
int16_t level = FetchSample(atariRam, ramSize, m_samplePtr);
if (stereo)
level += FetchSample(atariRam, ramSize, m_samplePtr + 1);

if (b50k)
{
m_50Acc += level;
m_50to25 ^= true;
if (!m_50to25)
{
m_currentDacLevel = (m_50Acc * m_masterVolume)>>1;
m_50Acc = 0;
}
}
else
{
m_currentDacLevel = level * m_masterVolume;
}

m_samplePtr += stereo?2:1;
if (m_samplePtr == m_sampleEndPtr)
{
mfp.SetSteDacExternalEvent();
Expand All @@ -155,9 +186,10 @@ int16_t SteDac::ComputeNextSample(const int8_t* atariRam, uint32_t ramSize, Mk68
}
m_innerClock -= m_hostReplayRate;
}

}
return level;
else
m_currentDacLevel = 0;
return m_currentDacLevel;
}

// emulate internal rol to please any user 68k code reading & waiting the complete cycle
Expand Down
3 changes: 3 additions & 0 deletions AtariAudio/SteDac.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,7 @@ class SteDac
int m_microwireShift;
uint8_t m_regs[256];
int m_masterVolume;
bool m_50to25;
int m_50Acc;
int16_t m_currentDacLevel;
};
2 changes: 1 addition & 1 deletion AtariAudio/ym2149c.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Ym2149c
void WriteReg(int reg, uint8_t value);
uint16_t Tick();

static const uint32_t kDcAdjustHistoryBit = 9; // 512 values
static const uint32_t kDcAdjustHistoryBit = 11; // 2048 values (~20ms at 44Khz)

int16_t dcAdjust(uint16_t v);

Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ ATARI-ST SNDH ZIP Archive music browser/player by [Leonard/Oxygene](https://twit

# Versions

- v0.5 : reload last loaded SNDH archive, bug fixes for some SNDH
- v0.4 : per voice visualization oscilloscopes, 2MiB emulated Atari machine, AtariAudio API cleanup, some optimizations
- v0.3 : WAV export, play/pause button, and low CPU usage when app minimized
- v0.2 : SNDH music are time seekable! enjoy!
- v0.1 : first version
- v0.60 : Tao "MS3" songs support! Added subsong count in list
- v0.50 : reload last loaded SNDH archive, bug fixes for some SNDH
- v0.40 : per voice visualization oscilloscopes, 2MiB emulated Atari machine, AtariAudio API cleanup, some optimizations
- v0.30 : WAV export, play/pause button, and low CPU usage when app minimized
- v0.20 : SNDH music are time seekable! enjoy!
- v0.10 : first version



Expand Down
14 changes: 12 additions & 2 deletions SndhArchivePlayer/SndhArchive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ SndhArchive::SndhArchive()
m_filteredList = NULL;
m_filterdSize = 0;
m_asyncZipThread = NULL;
m_firstSearchFocus = false;
}

SndhArchive::~SndhArchive()
Expand Down Expand Up @@ -52,6 +53,7 @@ void SndhArchive::AsyncBrowseArchive()
itemOut.title = info.musicName ? _strdup(info.musicName) : _strdup(fname);
itemOut.duration = info.playerTickCount / info.playerTickRate;
itemOut.year = NULL;
itemOut.subsongCount = info.subsongCount;
outSize++;
}
}
Expand All @@ -61,6 +63,7 @@ void SndhArchive::AsyncBrowseArchive()
zip_entry_close(m_zipArchive);
}

m_firstSearchFocus = true;
m_size = outSize;
qsort((void *)m_list, (size_t)m_size, sizeof(PlayListItem), fEntrySort);
RebuildFilterList();
Expand Down Expand Up @@ -175,6 +178,11 @@ void SndhArchive::ImGuiDraw(SndhArchivePlayer& player)
{
ImGui::Text("Search:");
ImGui::SameLine();
if (m_firstSearchFocus)
{
ImGui::SetKeyboardFocusHere();
m_firstSearchFocus = false;
}
if (m_ImGuiFilter.Draw("Found:"))
RebuildFilterList();

Expand All @@ -198,10 +206,11 @@ void SndhArchive::ImGuiDraw(SndhArchivePlayer& player)
*/
if (ImGui::BeginTable("table_advanced", 4, flags))
{
ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
ImGui::TableSetupColumn("Author", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 120.0f, 0);
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, 1);
ImGui::TableSetupColumn("Duration", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, 2);
ImGui::TableSetupColumn("Year", ImGuiTableColumnFlags_PreferSortDescending, 0.0f, 3);
ImGui::TableSetupColumn("Sub-Song", ImGuiTableColumnFlags_PreferSortDescending, 0.0f, 3);

ImGui::TableHeadersRow();

Expand Down Expand Up @@ -242,7 +251,8 @@ void SndhArchive::ImGuiDraw(SndhArchivePlayer& player)
ImGui::TextUnformatted("?");

ImGui::TableSetColumnIndex(3);
ImGui::TextUnformatted(item.year);
if ( item.subsongCount>1)
ImGui::Text("%d", item.subsongCount);

ImGui::PopID();
}
Expand Down
2 changes: 2 additions & 0 deletions SndhArchivePlayer/SndhArchive.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class SndhArchive
const char* author;
const char* year;
int duration;
int subsongCount;
};

void RebuildFilterList()
Expand Down Expand Up @@ -72,5 +73,6 @@ class SndhArchive
std::thread* m_asyncZipThread;
std::atomic<bool> m_asyncDone;
std::atomic<int> m_progress;
bool m_firstSearchFocus;

};
3 changes: 1 addition & 2 deletions SndhArchivePlayer/SndhArchivePlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include "SndhArchivePlayer.h"
#include "SndhArchive.h"
#include "AsyncSndhStream.h"
//#include "extern/zip/src/zip.h"

static const int kHostReplayRate = 44100;
static const int kLatencySampleCount = kHostReplayRate / 60;
Expand Down Expand Up @@ -456,7 +455,7 @@ void SndhArchivePlayer::UpdateImGui()

if (ImGui::BeginPopupModal("About", NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
DrawTextCentered("SNDH Archive Player v0.5");
DrawTextCentered("SNDH Archive Player v0.60");
ImGui::Separator();
extern void OsOpenInShell(const char* path);

Expand Down
2 changes: 1 addition & 1 deletion SndhArchivePlayer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmd
//ImGui_ImplWin32_EnableDpiAwareness();
WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr };
::RegisterClassExW(&wc);
HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"SNDH-Archive Player v0.5", WS_OVERLAPPEDWINDOW, 100, 100, 800, 800, nullptr, nullptr, wc.hInstance, nullptr);
HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"SNDH-Archive Player v0.60", WS_OVERLAPPEDWINDOW, 100, 100, 800, 800, nullptr, nullptr, wc.hInstance, nullptr);

// Initialize Direct3D
if (!CreateDeviceD3D(hwnd))
Expand Down
Binary file modified SndhArchivePlayer_x64.exe
Binary file not shown.
50 changes: 25 additions & 25 deletions imgui.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,27 @@ Collapsed=0

[Window][Song Info]
Pos=0,0
Size=314,207
Size=314,208
Collapsed=0
DockId=0x00000007,0

[Window][Oscilloscope]
Pos=316,0
Size=468,207
Size=468,208
Collapsed=0
DockId=0x00000006,0

[Window][File Viewer]
Pos=0,375
Size=784,386
Pos=0,210
Size=784,369
Collapsed=0
DockId=0x00000002,1
DockId=0x00000004,1

[Window][SNDH Archive]
Pos=0,375
Size=784,386
Pos=0,210
Size=784,369
Collapsed=0
DockId=0x00000002,0
DockId=0x00000004,0

[Window][Oscilloscope2]
ViewportPos=352,301
Expand Down Expand Up @@ -75,10 +75,10 @@ Size=376,162
Collapsed=0

[Window][Emulation]
Pos=0,209
Size=784,164
Pos=0,581
Size=784,180
Collapsed=0
DockId=0x00000001,0
DockId=0x00000002,0

[Window][Final output]
Pos=369,0
Expand All @@ -87,8 +87,8 @@ Collapsed=0
DockId=0x00000008,0

[Window][About]
Pos=326,234
Size=246,292
Pos=323,217
Size=260,327
Collapsed=0

[Table][0x20DF7A63,4]
Expand All @@ -104,19 +104,19 @@ Column 0 Sort=0v

[Table][0x491AF374,4]
RefScale=13
Column 0 Width=129
Column 1 Width=345
Column 2 Width=69
Column 0 Width=175
Column 1 Width=372
Column 2 Width=127
Column 3 Weight=1.0000

[Docking][Data]
DockSpace ID=0x8B93E3BD Window=0xA787BDB4 Pos=108,131 Size=784,761 Split=Y Selected=0xD28CF431
DockNode ID=0x00000003 Parent=0x8B93E3BD SizeRef=784,197 Split=X Selected=0xD28CF431
DockNode ID=0x00000005 Parent=0x00000003 SizeRef=314,197 Split=X Selected=0xD28CF431
DockNode ID=0x00000007 Parent=0x00000005 SizeRef=367,197 CentralNode=1 Selected=0xD28CF431
DockNode ID=0x00000008 Parent=0x00000005 SizeRef=353,197 Selected=0x3B6A65F4
DockNode ID=0x00000006 Parent=0x00000003 SizeRef=468,197 Selected=0x6D682373
DockNode ID=0x00000004 Parent=0x8B93E3BD SizeRef=784,552 Split=Y Selected=0x3497E769
DockNode ID=0x00000001 Parent=0x00000004 SizeRef=784,164 Selected=0x578BBCCF
DockNode ID=0x00000002 Parent=0x00000004 SizeRef=784,386 Selected=0x3497E769
DockSpace ID=0x8B93E3BD Window=0xA787BDB4 Pos=108,131 Size=784,761 Split=Y Selected=0xD28CF431
DockNode ID=0x00000001 Parent=0x8B93E3BD SizeRef=784,579 Split=Y
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=784,208 Split=X Selected=0xD28CF431
DockNode ID=0x00000005 Parent=0x00000003 SizeRef=314,197 Split=X Selected=0xD28CF431
DockNode ID=0x00000007 Parent=0x00000005 SizeRef=367,197 CentralNode=1 Selected=0xD28CF431
DockNode ID=0x00000008 Parent=0x00000005 SizeRef=353,197 Selected=0x3B6A65F4
DockNode ID=0x00000006 Parent=0x00000003 SizeRef=468,197 Selected=0x6D682373
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=784,369 Selected=0x3497E769
DockNode ID=0x00000002 Parent=0x8B93E3BD SizeRef=784,180 Selected=0x578BBCCF

0 comments on commit f2af36f

Please sign in to comment.