From: Shamus Hammons Date: Thu, 3 Jan 2019 13:44:30 +0000 (-0600) Subject: Move saving code to fileio, add WOZ2 support, misc. DSP tweaks. X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=98e7923e3e81d05395dbadf4c4f2fba137feeff1;p=wozmaker Move saving code to fileio, add WOZ2 support, misc. DSP tweaks. --- diff --git a/.gitignore b/.gitignore index c089a6d..ad3055e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ analysis1.ods wozmaker Makefile res/*.xcf +.qmake.stash diff --git a/src/analysisthread.cpp b/src/analysisthread.cpp index bd9daea..138da3a 100644 --- a/src/analysisthread.cpp +++ b/src/analysisthread.cpp @@ -49,14 +49,24 @@ void AnalysisThread::run() if (Global::a2r == NULL) return; -//temp, until we get the AA filled ones sorted -// for(uint32_t i=0; i<141; i++) - for(uint32_t i=0; i<139; i++) + // Run full tracks first + for(uint32_t i=0; i<141; i+=4) { SynthesizeTrack(i); -// usleep(10000); - int a = random(); - Global::trackStatus[i] = a & 0x03; + int a = random() & 0x03; + Global::trackStatus[i] = (a == 0 ? 3 : a); + emit(ShowTracks()); + } + + // Then fill in with half/quarter tracks + for(uint32_t i=0; i<141; i++) + { + if ((i % 4) == 0) + continue; + + SynthesizeTrack(i); + int a = random() & 0x03; + Global::trackStatus[i] = (a == 0 ? 3 : a); emit(ShowTracks()); } } diff --git a/src/dsp.cpp b/src/dsp.cpp index 98800a2..96f0a0b 100644 --- a/src/dsp.cpp +++ b/src/dsp.cpp @@ -17,11 +17,8 @@ //#define NOISY // Really, there shouldn't be more than 5 waveforms per track -//static uint32_t total = 0;//trkStrms -//static uint32_t slip[9]; -//double ratio[9]; -uint32_t sNum[9]; -double initSyncTime[9]; +uint32_t sNum[6]; +double initSyncTime[6]; static const double SIGMA_THRESHOLD = 2.5; @@ -41,16 +38,14 @@ double StdDeviation(double * a, uint32_t num, double * pMean/*= NULL*/) for(uint32_t i=0; i= Global::streamLen[i]) - return swLen; - } - - // Save these *before* we step forward - memcpy(syncSave, syncPt, sizeof(syncSave)); - StepForward(syncPt, a, num); - double mean; - double sigma = StdDeviation(a, num, &mean); - - if (sigma <= SIGMA_THRESHOLD) - { - for(uint32_t i=0; i %.2lf {drift=%.2lf, la=%d}\n", sigma, driftSigma, lookahead); -#endif - // New heuristic: if the sigma of the current row is less than the sigma of the drift over the last 32 steps, we consider that to be "in sync"; otherwise, do the usual stuff -/* -This works until you hit this: -a: [1167.00][1174.00][1169.00] => 2.94 - ~~~~ -<1167.00><1174.00><1169.00> ==> 2.94 {drift=0.82}(!!!) (lookahead=2.94, 630) -{12168}-{12166}-{12166} - ~~~~ -<1198.00><1205.00><1200.00> ==> 2.94 {drift=0.82} (lookahead=0.00, 629) -{12169}-{12167}-{12167} - ~~~~ -<1231.00><1238.00><1233.00> ==> 2.94 {drift=0.82} (lookahead=0.00, 628) ----------------- -<337.00><334.00><335.00> ==> 1.25 (OK) (lookahead=18.40, 1705) -{1260}-{1259}-{1258} -a: [1111.00][1100.00][1097.00] => 6.02 {drift=7.72, la=0} -a: [42.00][51.00][45.00] => 3.74 {drift=7.72, la=150} - 20.00 ~~~~ 0.00 -< 62.00>< 51.00>< 45.00> ==> 7.04 (lookahead=13.42, 0) -{2972}-{2970}-{2969} - ~~~~ 20.00 13.00 <-- the more I look at it, the more I think we need to coalesce these into their next steps... (can be done in StepForward/Back()) -------------------- -it does OK but fails because we don't check *inside* the loop -<363.00><364.00><364.00> ==> 0.47 (OK) (lookahead=52.33, 1704) -{25947}-{25931}-{25922} -a: [33.00][15.00][47.00] => 13.10 {drift=3.86, la=150} - 1149.00 1158.00 ~~~~ -<1182.00><1173.00>< 47.00> ==> 532.94 (lookahead=40.94, 0) -{27657}-{27641}-{27627} - ~~~~ 31.00 1155.00 -<1182.00><1204.00><1202.00> ==> 9.93 (lookahead=46.20, 6) -{27657}-{27642}-{27633} - 31.00 ~~~~ 0.00 -<1213.00><1204.00><1202.00> ==> 4.78 (lookahead=0.00, 149) -{27658}-{27642}-{27633} - -*/ - // We check for large zero areas for the new heuristic -//buuuuuuuut... it fails for the stuff that tags along at the end, so... -/* -After looking at this long and hard, and thinking about the fairly random nature of the disk speed as it turns, I've come to the conclusion that trying to use the local speed drift (whatever that means) is futile. It's random; it just doesn't correlate, period. So stuff like the following is pretty much crap. -*/ - if ((mean > 9.0)//00.0) - && ((sigma < StdDeviation(drift, num)) - || (((sigma + nextSigma) / 2.0) < SIGMA_THRESHOLD))) - { - doSync = false; - } - - if (doSync) - { - do - { - syncSteps++; - - // If we've been in this loop too long, something's very wrong - if (syncSteps > 20) - return swLen; - - // Pull the lesser streams forward to catch up to the largest - uint32_t largestIdx = LargestIdx(a, num); - pulled = false; - - for(uint32_t i=0; i 7.0) - { - pulled = true; - - if (walkahead >= Global::streamLen[i]) - { - // We ran out of road, so we're done for now - return swLen; - } -/* -Maybe rename this to StepForwardSngl and the other to StepForwardAll? -because otherwise, this can become murky -[well, should be able to tell from the context. -well, the thing that's murky is the all clears the array while the single adds to the existing. now *that's* confusing... :-P] -we can call it StepAndAddForward/Back; that would clear it up. -*/ - StepAndAddForward(walkahead, ttn, i); - } - - syncPt[i] = walkahead; - a[i] += ttn; -#ifdef NOISY - if (pulled) - printf(" %6.2lf ", ttn); - else - printf(" "); -#endif - } - -#ifdef NOISY - printf("\n"); - - for(uint32_t i=0; i", a[i]); -#endif - // Calculate the standard deviation at this new point - sigma = StdDeviation(a, num, &mean); -#ifdef NOISY - printf(" ==> %.2lf%s", sigma, (sigma <= SIGMA_THRESHOLD ? " (OK)" : (!pulled ? "(STEP)" : ""))); + if (a1[i] != a2[i]) + return false; + } -double lookahead[9]; -//printf(" {drift=%.2lf}", driftSigma); -uint32_t minSyncIdx = SmallestIdx(syncPt, num); -if (syncPt[minSyncIdx] > 0) -{ - for(uint32_t i=0; i SIGMA_THRESHOLD) && !pulled) - { - for(uint32_t i=0; i SIGMA_THRESHOLD) && pulled); - } - - // Now, we've re-established sync, now fill the appropriate spots - -/* -So the algorithm to do this proppaly is like so: - -Step 1: Find the smallest step forward through the section; set amplitude to 0.2. -Step 2: Loop thru the other streams and see if they correspond. If so, advance their stream start & add 0.2 to the amplitude for each one seen. -Step 3: Add the mean value of the corresponding values to the synthesized waveform + wave amplitude -Step 4: If all of the stream starts are at the end of the section, we are done. -[maybe. how do you handle the case where you have streams that look like so: - -200 -150 50 -150 50 -175 25 -200 - -.......................................| -.............................|.........| -.............................|.........| -..................................|....| -.......................................| - -this will fail to add in the correct amount for the times that had no part in the anomaly. so to fix this, maybe have a baseline value that bumps upward to show where the "cursor" (so to speak) is, so at the end we can subtract the mean that we got above from this baseline to get the remaining time to synthesize, like so: - -synthWave[swLen] = (uint32_t)((mean - baseline) + 0.5) -swAmplitude[swLen] = amplitude; - -no need for that. the times that step directly to the end can safely be ignored. -] - -150 -> 150 (ignores 175) -150 goes in, ampl. .4, we now have: - -200 -50 -50 -175 25 -200 - -only one is left that we can grab: - -175 - -last pulse was at 150 (40%), so we need to subtract that out - --> 25 - -so maybe we'd do like so: --1) create a list containing the start values for the start of the anomalous section and replace them as the counters advance. -0) are streams at the end? if so, stuff in the final value to the synthesized wave & stop, otherwise: -1) find the smallest in the current row and use that as a basis. -2) find streams that correlate, if any -3) advance the streams that correlate & subtract out the minimum from the other rows -4) go to 0) - -200 -150 50 -150 50 -175 25 -200 - -smallest is 150: pick 150 -> picks up 150 -advance the 150 rows & subtract 150 from the rest: - -50 -50 -50 -25 25 -50 - -pick smallest: 25 -> picks up nothing -advance the 25 & subtract it from the rest: - -25 -25 -25 -25 -25 - -We've reached the end of the section, add the final amount - --------------------------------------------------------------------------------- -syncSave before: [2->4][2->6][2->4][2->6][2->6] -syncSave after: [3->4][3->6][3->4][3->6][3->6] - -currentRow: [120.89][49.97][46.98][49.98][48.98] => 28.78 - -2: [3->4][3->6][3->4][3->6][3->6] - -a[0]=46.98: [120.89] ==> 36.95 - [49.97]{17.00} ==> 1.50 - <106.00>[49.97][49.98]{28.00} ==> 1.41 - [49.97][49.98][48.98]{26.00} ==> 1.22 - -3: [3->4][4->6][4->4][4->6][4->6] - -a[0]=17.00: [73.91] ==> 28.45 - <56.00>[28.00]{45.00} ==> 5.50 - [28.00][26.00]{47.00} ==> 4.78 - -4: [3->4][5->6][4->4][5->6][5->6] - -a[0]=45.00: [56.91] ==> 5.95 - [56.00]{32.00} ==> 5.50 - <32.00>[56.00][47.00]{32.00} ==> 4.78 - -5: [3->4][6->6][4->4][6->6][6->6] - -a[0]=11.91: <32.00> - -6: [4->4][6->6][4->4][6->6][6->6] - 2->4 2->6 2->4 2->6 2->6 -[120.89][ 49.97][ 46.98][ 49.98][ 48.98] => 28.78 -( 73.91) 17.00 106.00 28.00 26.00 -( 56.91) 56.00 45.00 47.00 - 32.00 32.00 32.00 32.00 - -*/ -/*printf("syncSave before: "); -for(uint32_t i=0; i%d]", syncSave[i], syncPt[i]); -printf("\n");//*/ - // Collect the current row - StepForward(syncSave, currentRow, num); - bool done2; - float ampStep = 1.0f / (float)num; +uint32_t IndexForTime(uint32_t trackNum, uint32_t time) +{ + uint32_t curTime = 0, pos = 0; -/*printf("syncSave after: "); -for(uint32_t i=0; i%d]", syncSave[i], syncPt[i]); -printf("\n"); -printf("currentRow: "); -for(uint32_t i=0; i %.2lf\n", StdDeviation(currentRow, num));//*/ + while (curTime < time) + curTime += Global::synWave[trackNum][pos++]; - done2 = true; + return pos; +} -//printf("%d: ", swLen); - for(uint32_t i=0; i%d]", syncSave[i], syncPt[i]); - if (syncSave[i] != syncPt[i]) - { - done2 = false; -// break; - } - } -//printf("\n"); - - while (!done2) - { - float amplitude = ampStep; - uint32_t smallestIdx = SmallestIdx(currentRow, num); - uint32_t cnt = 1; - a[0] = currentRow[smallestIdx]; -//printf("a[0]=%.2lf: ", a[0]); - - for(uint32_t i=0; i= Global::streamLen[i]) - return swLen; - - if (i == smallestIdx) - { - currentRow[i] = 0; - StepAndAddForward(syncSave[i], currentRow[i], i); -//printf("<%.2lf>", currentRow[i]); - - // Make sure no spurious signals are looked at - if ((syncSave[i] < syncPt[i]) && (currentRow[i] < 24.0)) - StepAndAddForward(syncSave[i], currentRow[i], i); - - continue; - } - - double crSave = currentRow[i]; - currentRow[i] -= a[0]; - - // Don't bother with stuff that's out of range! :-P - if (syncSave[i] == syncPt[i]) - continue; - - // Try to find correlates - a[cnt] = crSave;//currentRow[i]; - cnt++; - sigma = StdDeviation(a, cnt, &mean); -//for(uint32_t j=1; j %.2lf\n\t", sigma); - } - - sigma = StdDeviation(a, cnt, &mean); - synthWave[swLen] = (uint32_t)(mean + 0.5); - swAmplitude[swLen] = amplitude; - swLen++; - done2 = true; - -//printf("%d: ", swLen); - for(uint32_t i=0; i%d]", syncSave[i], syncPt[i]); - if (syncSave[i] != syncPt[i]) - { - done2 = false; -// break; - } - } -//printf("\n"); - } - - sigma = StdDeviation(currentRow, num, &mean); - synthWave[swLen] = mean; - swAmplitude[swLen] = 1.0f; - swLen++; - } - } - - return swLen; -} - - -// -// Attempt to find the sync point for the passed in stream #s. If found, set -// sync1 & sync2 to the spots where sync was found (typically, one or the other -// will be zero) and return true, otherwise return false. -// -bool FindSync(uint32_t stream1, uint32_t stream2, uint32_t & sync1, uint32_t & sync2) -{ - sync1 = sync2 = 0; - - // We *should* be able to synchronize within around 80 fluxes or so. If not, then there's bigger problems. - for(uint32_t offset=0; offset<80; offset++) - { - uint32_t strmLen = Uint32LE(Global::stream[stream1]->dataLength); - bool found = true; - - // How many bits should we consider as synchronized? All of them? - for(uint32_t i=1, i2=1; idata[i]; - double time2 = (double)Global::stream[stream2]->data[i2 + offset]; - - while (Global::stream[stream1]->data[i] == 0xFF) - { - i++; - time1 += (double)Global::stream[stream1]->data[i]; - } - - while (Global::stream[stream2]->data[i2] == 0xFF) - { - i2++; - time2 += (double)Global::stream[stream2]->data[i2 + offset]; - } - - double mean = (time1 + time2) * 0.5; - double sigma = sqrt(0.5 * (((time1 - mean) * (time1 - mean)) - + ((time2 - mean) * (time2 - mean)))); - - if (sigma > 2.50) - { - // How many bits is enough to say we found it? -/* -N.B.: This (1,000) is fine for Apple Panic (which has shitty captures with junk in between sectors), but not for Championship Lode Runner which doesn't have any sync bytes for a loooooooooooong time -*/ - if (i < 10000) - found = false; - - break; - } - } - - if (found) - { - sync2 = offset; - return true; - } - } - - // Since we didn't find sync moving stream 2 forward, let's try stream 1 - for(uint32_t offset=0; offset<80; offset++) - { - uint32_t strmLen = Uint32LE(Global::stream[stream2]->dataLength); - bool found = true; - - // How many bits should we consider as synchronized? All of them? - for(uint32_t i=1, i2=1; idata[i]; - double time2 = (double)Global::stream[stream1]->data[i2 + offset]; - - while (Global::stream[stream2]->data[i] == 0xFF) - { - i++; - time1 += (double)Global::stream[stream2]->data[i]; - } - - while (Global::stream[stream1]->data[i2] == 0xFF) - { - i2++; - time2 += (double)Global::stream[stream1]->data[i2 + offset]; - } - - double mean = (time1 + time2) * 0.5; - double sigma = sqrt(0.5 * (((time1 - mean) * (time1 - mean)) - + ((time2 - mean) * (time2 - mean)))); - - if (sigma > 2.50) - { - // How many bits is enough to say we found it? - if (i < 10000) - found = false; - - break; - } - } - - if (found) - { - sync1 = offset; - return true; - } - } - - return false; -} - - -void FindSyncForStreams(uint32_t * syncPt, uint32_t num) -{ -// uint32_t syncPt[10] = { 0 }; - uint32_t base = 0; - syncPt[0] = 0; - - for(uint32_t i=1; idataLength); j++) - { - uint32_t timeToNext = Global::streamData[i][j]; - - while (Global::streamData[i][j] == 0xFF) - { - j++; - timeToNext += Global::streamData[i][j]; - } - - initSyncTime[i] += (double)timeToNext; - - if ((timeToNext >= 24) && (timeToNext <= 49)) - bitPat = (bitPat << 1) | 1; - else if ((timeToNext >= 50) && (timeToNext <= 80)) - bitPat = (bitPat << 2) | 1; - else if ((timeToNext >= 81) && (timeToNext <= 112)) - bitPat = (bitPat << 3) | 1; - else - { - while (timeToNext > 32) - { - bitPat <<= 1; - timeToNext -= 32; - } - } - - if (i == 0) - bitPat0 = bitPat; - - // Search for first instance of 3 FF. or 3 FF.. in bitstream - // Might need to look for FE.. as well - // 0 1111 1111 0111 1111 1011 1111 1101 - // 0111 1111 1001 1111 1110 0111 1111 1001 -// if (((bitPat & 0x1FFFFFFF) == 0x0FF7FBFD) -// || (bitPat & 0xFFFFFFFF) == 0x7F9FE7F9) - // Need to see at least two regular bytes after as well: - // 0 1111 1111 0111 1111 1011 1111 1101 xxxx xxx1 xxxx xxx1 - // 0111 1111 1001 1111 1110 0111 1111 1001 xxxx xxx1 xxxx xxx1 - if ((bitPat & 0x1FFFFFFF0101) == 0x0FF7FBFD0101) - { - if ((i != 0) && (bitPat != bitPat0)) - continue; - - sync[i] = j - (j - 25 >= 0 ? 25 : 0); - break; - } - else if ((bitPat & 0xFFFFFFFF0101) == 0x7F9FE7F90101) - { - if ((i != 0) && (bitPat != bitPat0)) - continue; - - sync[i] = j - (j - 25 >= 0 ? 25 : 0); - break; - } - } - } -} - - -// -// Walk through the streams backwards until we hit the zero point on one of them. This assumes the sync point we found initially is a good one (it might not be!). -// -void BacktrackInitialSync(uint32_t * syncPt, uint32_t num) -{ -// uint32_t count = 0; - double a[10]; -// uint32_t syncSave[10]; - - // Save the original sync points (do we need to?) -// for(uint32_t i=0; i 0) - { - // Get the time for this step into a[] - for(uint32_t i=0; idata[syncPt[i]];// * ratio[i]; - - while ((syncPt[i] > 0) - && (Global::stream[sNum[i]]->data[syncPt[i] - 1] == 0xFF)) - { - syncPt[i]--; - a[i] += (double)Global::stream[sNum[i]]->data[syncPt[i]];// * ratio[i]; - } - } - - double sigma = StdDeviation(a, num); -// count++; - - if (sigma > SIGMA_THRESHOLD) - { - printf("\n"); - - for(uint32_t i=0; i", (double)Global::stream[sNum[i]]->data[syncPt[i]]);// * ratio[j]); - printf("<%6.2lf>", a[i]);// * ratio[j]); - - printf(" --> %.2lf\n", sigma); - - uint32_t syncCount = 0; - - // Save sync origins for later analysis -// for(uint32_t j=0; j 3.30)//SIGMA_THRESHOLD) - { - // Deal with the problem. The heuristic is find the largest value in the set, then advance the other streams by one step until they are "close" to the largest. If the std. deviation is too large, try again; eventually it should be within good limits. - uint32_t largestIdx = LargestIdx(a, num); - - for(uint32_t i=0; idata[walkBack]; - - while ((walkBack > 0) - && (Global::stream[sNum[i]]->data[walkBack - 1] == 0xFF)) - { - walkBack--; - ttn += (double)Global::stream[sNum[i]]->data[walkBack];// * ratio[i]; - } - - // If the difference between the highest and this is over 5, add the next time interval and let the sync counter, uh, slip (backwards!) :-) - if ((a[largestIdx] - a[i]) > 5.0) - { - syncPt[i] = walkBack; - a[i] += ttn; - printf(" %6.2lf ", ttn); - } - else - printf(" "); - } - - printf("\n"); - - for(uint32_t i=0; i", a[i]); - - sigma = StdDeviation(a, num); - printf(" ==> %.2lf\n", sigma); - - syncCount++; - - if (syncCount > 20) - { - // Back up the train - for(uint32_t i=0; i= 40 ? 40 : 0); - - if ((int32_t)syncPt[i] < 0) - syncPt[i] = 0; - } - - minSlip = 0; - printf("Could not synchronize streams...\n"); - break; - } - } - } - - // Point as the next time step and see where the minimum sync point is now... - for(uint32_t i=0; i 0) - { - // Get the time for this step into a[] - for(uint32_t i=0; idata[syncPt[i]];// * ratio[i]; - - while ((syncPt[i] > 0) - && (Global::stream[sNum[i]]->data[syncPt[i] - 1] == 0xFF)) - { - syncPt[i]--; - a[i] += (double)Global::stream[sNum[i]]->data[syncPt[i]];// * ratio[i]; - } - } - - double sigma = StdDeviation(a, num); - - if (sigma > SIGMA_THRESHOLD) - { - uint32_t syncCount = 0; - - // Save sync origins for later analysis - memcpy(syncSave, syncPt, sizeof(syncSave)); - - // It may turn out that this is too large too... - while (sigma > SIGMA_THRESHOLD) - { - // Deal with the problem. The heuristic is find the largest value in the set, then advance the other streams by one step until they are "close" to the largest. If the std. deviation is too large, try again; eventually it should be within good limits. - uint32_t largestIdx = LargestIdx(a, num); - - // We now pull all streams "forward" until they are within 7 - // underneath the largest or past it. - for(uint32_t i=0; i 7.0) - { - if (walkback <= 0) - { - memcpy(syncPt, syncSave, sizeof(syncSave)); - printf("Synchronized as far back as possible...\n"); - return; - } - - walkback--; - ttn += (double)Global::stream[sNum[i]]->data[walkback];// * ratio[i]; - - while ((walkback > 0) - && (Global::stream[sNum[i]]->data[walkback - 1] == 0xFF)) - { - walkback--; - ttn += (double)Global::stream[sNum[i]]->data[walkback];// * ratio[i]; - } - } - - syncPt[i] = walkback; - a[i] += ttn; - } - - sigma = StdDeviation(a, num); - - syncCount++; - - if (syncCount > 20) - { - // Back up the train - for(uint32_t i=0; i= 40 ? 40 : 0); - - if ((int32_t)syncPt[i] < 0) - syncPt[i] = 0; - } - - minSlip = 0; - printf("Could not synchronize streams...\n"); - break; - } - } - } - - // Point as the next time step and see where the minimum sync point is now... - for(uint32_t i=0; i SIGMA_THRESHOLD) - { - uint32_t syncCount = 0; - bool pulled; - - do - { - syncCount++; - - if (syncCount > 20) - { - // Back up the train - for(uint32_t i=0; i= 40 ? 40 : 0); - - if ((int32_t)sync[i] < 0) - sync[i] = 0; - } - - printf("Could not synchronize streams...\n"); - return; - } - - // Deal with the problem. The heuristic is find the largest value in the set, then advance the other streams by one step until they are "close" to the largest. If the std. deviation is too large, try again; eventually it should be within good limits. - uint32_t largestIdx = LargestIdx(a, num); - pulled = false; - - // We now pull all streams "forward" until they are within 7 - // underneath the largest or past it. - for(uint32_t i=0; i 7.0) - { - pulled = true; - - if ((int32_t)walkback <= 0) - { - memcpy(sync, syncSave, sizeof(syncSave)); - printf("Synchronized as far back as possible...\n"); - return; - } - - StepAndAddBack(walkback, ttn, i); - } - - sync[i] = walkback; - a[i] += ttn; - } - - // Calculate the standard deviation at this new point - sigma = StdDeviation(a, num); - - // Heuristic: see if we're stuck with a bad sigma and can't pull any more forward; if so, pull forward one step and see if that gets us any traction... - if ((sigma > SIGMA_THRESHOLD) && !pulled) - { - for(uint32_t i=0; i SIGMA_THRESHOLD) && pulled); - } - } -} - - -void BacktrackInitialSync4(uint32_t * sync, uint32_t num) -{ - double a[9], a2[9]; - uint32_t syncSave[9]; - - while (true) - { - uint32_t minSlip = Smallest(sync, num); - - if (minSlip == 0) - break; - - // Save sync origins for later analysis if necessary - memcpy(syncSave, sync, sizeof(syncSave)); - - // Get the time for this step into a[] - StepBack(sync, a, num); - double sigma = StdDeviation(a, num); - - if (sigma > SIGMA_THRESHOLD) - { -printf("\n"); -for(uint32_t i=0; i", a[i]); } -printf(" --> %.2lf\n", sigma); - // Let's see if we can re-sync through this rough patch - int result = Resync(sync, a, num, -1); - - // Well, we failed to find synchronization... :-( - if (result == -1) - { - memcpy(sync, syncSave, sizeof(syncSave)); - return; - } - - // OK, we have a good result, but what kind (1=end, 0=sync OK)? - if (result == 0) - StepBack(sync, a2, num); - else if (result == 1) - { -for(uint32_t j=0; j ", sync[j]); } -printf("\n"); - StepBack(sync, a2, num); - return; - } - } - } -} - - -void StepBackUntilBad(uint32_t * sync, double * a, uint32_t num) -{ - while (true) - { - // See where the minimum sync point is now... - uint32_t minSlip = Smallest(sync, num); - - if (minSlip == 0) - break; - - // Get the time for this step into a[] - StepBack(sync, a, num); - double sigma = StdDeviation(a, num); - - if (sigma > SIGMA_THRESHOLD) - { - printf("\n"); - - for(uint32_t i=0; i", a[i]); - - printf(" --> %.2lf\n", sigma); - return; - } - } - - printf("---------------------------------------------------\nAT START\n\n"); -} - - -bool StepBackThruBad(uint32_t * sync, double * a, uint32_t num) -{ - // Deal with the problem. The heuristic is find the largest value in the set, then advance the other streams by one step until they are "close" to the largest. If the std. deviation is too large, try again; eventually it should be within good limits. - uint32_t largestIdx = LargestIdx(a, num); - -/* -New heuristic to try here: advance each stream until it comes within 7 on the bottom end or passes it altogether; check the sigma then. - -2nd heuristic: attempt to pull the next 'num' time all at once and *add* it to the current step, check the sigma to see if it's in tolerance (*and* check the lookahead). -*/ - for(uint32_t i=0; i 7.0) - { - seen = true; - StepAndAddBack(walkback, ttn, i); - } - - sync[i] = walkback; - a[i] += ttn; - - if (seen) - printf(" %6.2lf ", ttn); - else - printf(" "); - } - - printf("\n"); - - for(uint32_t i=0; i", a[i]); - - double sigma = StdDeviation(a, num); - printf(" ==> %.2lf%s", sigma, (sigma <= SIGMA_THRESHOLD ? " (OK)" : "")); - -double lookahead[9]; -for(uint32_t i=0; i 0) - && (Global::streamData[i][walkback - 1] == 0xFF)) - { - walkback--; - a[i] += (double)Global::streamData[i][walkback] * ratio[i]; - } - - sync[i] = walkback; - } -} - - -void StepAndAddBack(uint32_t * sync, double * a, uint32_t num) -{ - for(uint32_t i=0; i 0) - && (Global::streamData[i][walkback - 1] == 0xFF)) - { - walkback--; - a[i] += (double)Global::streamData[i][walkback] * ratio[i]; - } - - sync[i] = walkback; - } -} - - -void StepAndAddBack(uint32_t & loc, double & a, uint32_t i) -{ - int32_t walkback = loc - 1; - a += (double)Global::streamData[i][walkback] * ratio[i]; - - while ((walkback > 0) - && (Global::streamData[i][walkback - 1] == 0xFF)) - { - walkback--; - a += (double)Global::streamData[i][walkback] * ratio[i]; - } - - loc = (uint32_t)walkback; -} - - -// -// Move every stream forward by one step -// -void StepForward(uint32_t * sync, double * a, uint32_t num) -{ - for(uint32_t i=0; i 0) - { - StepBack(tSync, a, num); - double sigma = StdDeviation(a, num); - - if (sigma > SIGMA_THRESHOLD) - break; - - count++; - smallestIdx = SmallestIdx(tSync, num); - } - } - else - { - uint32_t largestIdx = LargestIdx(tSync, num); - - while (tSync[largestIdx] < Global::streamLen[largestIdx]) - { - StepForward(tSync, a, num); - double sigma = StdDeviation(a, num); - - if (sigma > SIGMA_THRESHOLD) - break; - - count++; - largestIdx = LargestIdx(tSync, num); - } - } - - return count; -} - - -// -// Attempt to resynchronize the current streams -// N.B.: When we get here, we're already at the point *after* where it blew up -// the sigma (the times for that step are passed-in in "a") -// -// Returns -1 on failure, 0 is sync was successful, or 1 if reached end of -// stream before finding sync -// -int Resync(uint32_t * sync, double * a, uint32_t num, int32_t dir/*= 1*/) -{ - uint32_t syncCount = 0; - bool pulled; - double sigma = 0; - -for(uint32_t j=0; j 20) - { - // Back up the train - printf("Could not synchronize streams...\n"); - return -1; - } - - // Deal with the problem. The heuristic is find the largest value in the set, then advance the other streams by one step until they are "close" to the largest. If the std. deviation is too large, try again; eventually it should be within good limits. - uint32_t largestIdx = LargestIdx(a, num); - pulled = false; - - // We now pull all streams "forward" until they are within 7 - // underneath the largest or past it. - for(uint32_t i=0; i 7.0) - { - pulled = true; - - if (((dir == 1) && (walkback >= Global::streamLen[i])) - || ((dir == -1) && ((int32_t)walkback <= 0))) - { -// memcpy(sync, syncSave, sizeof(syncSave)); - printf("\nSynchronized as far back as possible...\n"); -for(uint32_t j=0; j", a[i]); - - // Calculate the standard deviation at this new point - sigma = StdDeviation(a, num); -printf(" ==> %.2lf%s", sigma, (sigma <= SIGMA_THRESHOLD ? " (OK)" : (!pulled ? "(STEP)" : ""))); - -double lookahead[9]; -uint32_t minSyncIdx = SmallestIdx(sync, num); -if (sync[minSyncIdx] > 0 && dir == -1) -{ -for(uint32_t i=0; i SIGMA_THRESHOLD) && !pulled) - { - if (dir == 1) - StepAndAddForward(sync, a, num); - else - StepAndAddBack(sync, a, num); - - sigma = StdDeviation(a, num);//, &mean); - pulled = true; - } - } - while ((sigma > SIGMA_THRESHOLD) && pulled); - -// double a2[9]; -// StepBack(sync, a2, num); - - return 0; -} - -#endif - - -// -// Compare two arrays to see if they are equal -// -bool Equal(uint32_t * a1, uint32_t * a2, uint32_t num) -{ - for(uint32_t i=0; i 2.50) - break; - - for(uint32_t i=0; i= Global::waveLen[sNum[i]])) - || ((dir == -1) && (sync[i] == 0))) - return count; - - sync[i] += dir; - } - - count++; - } - - return count; -} - - -uint32_t FindSyncBetweenFirstTwo(uint32_t * sync) -{ - uint32_t bestSync[2], bestLA = 0, syncSave = sync[0]; - - // Move the first stream first... - for(uint32_t i=0; i<200; i++) - { - uint32_t la = LookaheadWave(sync, 2); - - // See if the sync we've found is the best so far... - if (la > bestLA) - { - bestLA = la; - memcpy(bestSync, sync, sizeof(bestSync)); - } - - sync[0]++; - } - - // Otherwise, reset the first stream and move the 2nd - sync[0] = syncSave; - - for(uint32_t i=0; i<200; i++) - { - // We can bump this first since we already checked the [0][0] case above - sync[1]++; - uint32_t la = LookaheadWave(sync, 2); - - // See if the sync we've found is the best so far... - if (la > bestLA) - { - bestLA = la; - memcpy(bestSync, sync, sizeof(bestSync)); - } - } - - // Set sync to the best we found & return the best lookahead count - memcpy(sync, bestSync, sizeof(bestSync)); - - return bestLA; -} +// +// This is where we attempt to use the stream data to collapse them down to a single track. Taken as wholes, each individual track will drift out of sync with respect to the others, and fairly quickly as the drive mechanism does not read consistently at a set RPM as you might expect, but instead it fluctuates all over the place--which throws a big ol' monkey wrench into the works. (Yes, the overall *average* stays around a set RPM, but locally--nope.) +// +// The big problem is that the disk spins via a motor which isn't perfect in its rotation that is connected to the hub that spins the disk via a belt, which further adds more uncertainty to the speed of the disk as it rotates. The end result is that there is no consistency vis-a-vis the speed of the disk, and so the results of one read to the next can and will vary wildly. It's a miracle that these things are readable at all. O_o +// +// So how do we cope with it? I'm sure there's a well known paper or set of papers which addresses noise rejection from multiple signals read from a single source, but I have yet to find them. So what we have below is a set of ad-hoc assumptions and heuristics that attempt to deal with this problem. +// +// The basic assumption is that from any given pulse to the next one, the drift will tend to be small and thus as we move from pulse to pulse, we can stay more or less in sync by resetting the base from which we calculate the next time interval to the previous step. This works remarkably well until we run into a long period of zeroes, which seems to throw off the Applesauce hardware which read these streams in the first place; or when some spurious one pulses pop up in one stream that doesn't in one or more of the others. +// void FindInitialSyncForStreams2(uint32_t * sync, uint32_t num) { @@ -2230,7 +669,6 @@ printf(" => %.2lf\n", StdDeviation(currentRow, num));//*/ #endif -bool ResyncWave(uint32_t * sync, uint32_t num, int8_t dir = 1); bool ResyncWave(uint32_t * sync, uint32_t num, int8_t dir/*= 1*/) { double a[6]; @@ -2340,6 +778,94 @@ bool ResyncWave(uint32_t * sync, uint32_t num, int8_t dir/*= 1*/) } +uint32_t LookaheadWave(uint32_t * passedInSync, uint32_t num, int8_t dir/*= 1*/, bool * perfect/*= NULL*/) +{ + uint32_t sync[6]; + uint32_t count = 0; + memcpy(sync, passedInSync, sizeof(sync)); + + if (perfect) + *perfect = true; + + while (true) + { + if (StdDeviationWave(sync, num) > 2.50) + { + if (perfect) + *perfect = false; + + break; + } + + for(uint32_t i=0; i= Global::waveLen[sNum[i]])) + || ((dir == -1) && (sync[i] == 0))) + return count; + } + + count++; + } + + return count; +} + + +uint32_t FindSyncBetweenFirstTwo(uint32_t * sync) +{ + uint32_t bestSync[2], bestLA = 0, syncSave = sync[0]; + bool perfect; + + // Move the first stream first... + for(uint32_t i=0; i<200; i++) + { + uint32_t la = LookaheadWave(sync, 2, 1, &perfect); + + // See if the sync we've found is the best so far... + if (la > bestLA) + { + bestLA = la; + memcpy(bestSync, sync, sizeof(bestSync)); + } + + if (perfect) + break; + + sync[0]++; + } + + // Otherwise, reset the first stream and move the 2nd + sync[0] = syncSave; + + for(uint32_t i=0; i<200; i++) + { + // We can bump this first since we already checked the [0][0] case above + sync[1]++; + uint32_t la = LookaheadWave(sync, 2, 1, &perfect); + + // See if the sync we've found is the best so far... + if (la > bestLA) + { + bestLA = la; + memcpy(bestSync, sync, sizeof(bestSync)); + } + + if (perfect) + break; + } + + // Set sync to the best we found & return the best lookahead count + memcpy(sync, bestSync, sizeof(bestSync)); + + return bestLA; +} + + +// +// Walk backwards through the streams to try to find the starting point +// bool AttemptToFindStart(uint32_t * sync, uint32_t num) { // Sanity check... @@ -2391,10 +917,20 @@ bool InitialSync(uint32_t * sync, uint32_t num) { // Let's try a different approach to this... bool lookAt[6] = { true, true, false, false, false, false }; + uint32_t syncSave[2]; // while (FindSyncBetweenFirstTwo(sync) == false) - while (FindSyncBetweenFirstTwo(sync) < 1000) +// while (FindSyncBetweenFirstTwo(sync) < 1000) + while (true) { + memcpy(syncSave, sync, sizeof(syncSave)); + uint32_t bestSBFT = FindSyncBetweenFirstTwo(sync); + + if (bestSBFT >= 1000) + break; + + memcpy(sync, syncSave, sizeof(syncSave)); + for(uint32_t i=0; i bestLA) { @@ -2434,6 +971,12 @@ bool InitialSync(uint32_t * sync, uint32_t num) memcpy(syncBest, sync, sizeof(syncBest)); } + if (perfect || ((bestLA + j) == lookahead)) + { + j = 200; + break; + } + sync[i]++; } @@ -2455,7 +998,6 @@ bool InitialSync(uint32_t * sync, uint32_t num) } -uint32_t LoopLookahead(uint32_t trackNum, uint32_t start, uint32_t loopPoint, bool * test = NULL); uint32_t LoopLookahead(uint32_t trackNum, uint32_t start, uint32_t loopPoint, bool * test/*= NULL*/) { uint32_t count = 0; @@ -2543,7 +1085,7 @@ This is failing for track 9.00: it finds an initial sync @ 202, 200, la=1257 but else { #ifdef NOISYSYNTH - uint32_t startOfSynth = Global::synWaveLen[trackNum]; + uint32_t startOfSynth = Global::synWaveLen[trackNum]; #endif #ifdef NOISYSYNTH if (bloops < 2) @@ -2557,7 +1099,7 @@ This is failing for track 9.00: it finds an initial sync @ 202, 200, la=1257 but bloops++; // Count the # of times we've had to punt uint32_t syncSave[6] = { 0 }; memcpy(syncSave, sync, sizeof(syncSave)); - bool result = ResyncWave(sync, num); + /*bool result =*/ ResyncWave(sync, num); // Now go through the catty wampus crap and zero out the parts that aren't all ones across the board double timeToOnes = 0; @@ -2644,7 +1186,6 @@ for(uint32_t j=1; jestLoopPoint); uint32_t curTime = 0; @@ -2724,8 +1270,8 @@ We can start with the estimated loop point that the Applesauce hardware found, b double a[2]; uint32_t maxLookahead = 0; uint32_t maxPos = 0; - bool full, full2, full0, full1; - uint32_t blips, worstBlips, longestStretch, stretch, maxLongestStretch = 0, worstBlipsPos = 0, mlsPos = 0; + bool /*full, full2,*/ full0, full1; + uint32_t blips, worstBlips = 0, longestStretch, stretch, maxLongestStretch = 0, worstBlipsPos = 0, mlsPos = 0; worstBlips = 1e9; // Get the index to the correct time in "pos" @@ -2735,50 +1281,62 @@ We can start with the estimated loop point that the Applesauce hardware found, b printf("%.2f: estLoopTime=%d, curTime=%d, pos=%d\n", (float)trackNum / 4.0f, estLoopTime, curTime, pos); uint32_t posSave = pos; - // "pos" now holds the start of the search for our loop point. - for(uint32_t i=0; i<200; i++) + // First, see if we have basically a perfect loop out of the box (typically, all $AAs) + bool perfect; + mlsPos = pos; + worstBlipsPos = pos; + maxPos = pos; + maxLongestStretch = LoopLookahead(trackNum, 0, pos, &perfect); + + if (!perfect) { - uint32_t lookahead = 0; - uint32_t j, pos0; - bool first = true; - blips = 0; - longestStretch = stretch = 0; - startOfLoop = 0;//shouldn't be necessary... + worstBlips = 1e9; - for(j=(pos+i-100), pos0=0; j longestStretch) - longestStretch = stretch; + if (stretch > longestStretch) + longestStretch = stretch; - if (full0) - { - break; - } - else if (full1 && first) // only check 1st time (for now) - { - startOfLoop = 1; - lookahead = lla1; - stretch = lla1; - break; - } + if (full0) + { + break; + } + else if (full1 && first) // only check 1st time (for now) + { + startOfLoop = 1; + lookahead = lla1; + stretch = lla1; + break; + } - if (first) - first = false; + if (first) + first = false; - pos0 += lla0; - j += lla0; + pos0 += lla0; + j += lla0; - a[0] = Global::synWave[trackNum][pos0++]; - a[1] = Global::synWave[trackNum][j++]; - double sigma = StdDeviation(a, 2); + a[0] = Global::synWave[trackNum][pos0++]; + a[1] = Global::synWave[trackNum][j++]; #if 0 + double sigma = StdDeviation(a, 2); + if (first) { first = false; @@ -2793,16 +1351,6 @@ if (first) } #endif -/* if (sigma <= 2.50) - { - lookahead++; - stretch++; - - if (stretch > longestStretch) - longestStretch = stretch; - } - else//*/ -// { // Hmm, not in sync. See if we can re-sync stretch = 0; blips++; @@ -2823,8 +1371,7 @@ if (first) break; } while (true); -// } - } + } #if 0 if (trackNum == 137) @@ -2832,34 +1379,43 @@ if (trackNum == 137) #endif //maybe we should keep an array of the analyses so we can decide afterward which one is best... - if (blips < worstBlips) - { - worstBlips = blips; - worstBlipsPos = pos + i - 100; - } + if (blips < worstBlips) + { + worstBlips = blips; + worstBlipsPos = pos + i - 100; + } - if (lookahead > maxLookahead) - { - maxLookahead = lookahead; - maxPos = pos + i - 100; - } + if (lookahead > maxLookahead) + { + maxLookahead = lookahead; + maxPos = pos + i - 100; + } - if (longestStretch > maxLongestStretch) - { - maxLongestStretch = longestStretch; - mlsPos = pos + i - 100; - } + if (longestStretch > maxLongestStretch) + { + maxLongestStretch = longestStretch; + mlsPos = pos + i - 100; + } - if (blips == 0) - break; + if (blips == 0) + break; + } } +#endif #if 0 bitLen[trackNum] = RenderBitstream(bits[trackNum], &byteLen[trackNum], Global::synWave[trackNum], startOfLoop, maxPos); #endif - printf("%.2f: Synthesized wave length: %d\n", (float)trackNum / 4.0f , Global::synWaveLen[trackNum]); + if (perfect) + { + uint32_t estLoopTime = Uint32LE(Global::stream[sNum[0]]->estLoopPoint); + uint32_t pos = IndexForTime(trackNum, estLoopTime); + printf("Perfect loop point found at position %d (elp%+d, start=%d, end=%d)\n----------------------------------------------------------------------\n", loopEnd + 1, loopEnd + 1 - pos, loopStart, loopEnd); + } +#if 0 printf("%s loop point found at position %d (elp%+d, la=%d, startPos=%d, blips=%d, blipsPos=%d, longest stretch=%d, mlsPos=%d, sol=%d)\n----------------------------------------------------------------------\n", (blips == 0 ? "Perfect" : "Possible"), maxPos, maxPos - posSave, maxLookahead, pos, worstBlips, worstBlipsPos, maxLongestStretch, mlsPos, startOfLoop); +#endif /* Track 1.00: 36110 is the loop point. But it fails to find it for some reason. [Because it jumped on the first one it found instead of the longest...] @@ -2877,6 +1433,167 @@ Track 1.00: } +// +// Attempt to find where the track loop is. Passes back what it thinks they +// are in start and end. +// +bool FindLoopPoint(uint32_t trackNum, uint32_t & start, uint32_t & end) +{ +/* +Now, we take the track and make an ouroborus out of it by finding the sync point. We can also possibly use it to get rid of more false ones like we did with the resynchronization code. So how do we do this? + +We could use an approach similar to the original sync between 1 & 2, but there's no guarantee that the lookahead will be good right away. So we need to do a combination where we count the places where it coincides well and plow through spots where it doesn't (and possibly mask any ones in those areas if it's a good match). + +We can start with the estimated loop point that the Applesauce hardware found, by walking it a bit before that point we can make sure we don't miss it. +*/ + // We use the loop point from stream #1 because we're lazy (better would prolly be to take the average of all of them) + uint32_t estLoopTime = Uint32LE(Global::stream[sNum[0]]->estLoopPoint); + uint32_t pos = IndexForTime(trackNum, estLoopTime); + uint32_t posSave = pos; + + bool full0, full1, perfect; + +printf("%.2f: estLoopTime=%d, pos=%d\n", (float)trackNum / 4.0f, estLoopTime, pos); + + // First, see if we have basically a perfect loop out of the box + // (typically, a track of all $AAs) + LoopLookahead(trackNum, 0, pos, &perfect); + + if (perfect) + { + start = 0; + end = pos - 1; + return true; + } + + uint32_t bestMatchCount = 0, bestBlips = 1e9, longestStretch = 0; + uint32_t bestMatchCountPos = 0, bestBlipsPos = 0, longestStretchPos = 0; + + // "pos" now holds the start of the search for our loop point. + // Step from -99 to +99 around "pos" to find the loop point. If the input wave is very noisy, this might fail! + for(int32_t i=-99; i<100; i++) + { + uint32_t matchCount = 0; + uint32_t j, pos0; + bool first = true; + uint32_t blips = 0; + start = 0; + + for(j=pos+i, pos0=0; j longestStretch) + { + longestStretch = lla0; + longestStretchPos = pos + i; + } + + if (full0) + { + // If we found perfect sync and it's the first time, return + if (blips == 0) + { + end = pos + i - 1; + return true; + } + + // Otherwise, just break out of the loop since it might not be the best + break; + } + else if (full1 && first) // only check 1st time (for now) + { + // Since we found perfect sync, return + start = 1; + end = pos + i - 1; + return true; + } + + if (first) + first = false; + + pos0 += lla0; + j += lla0; + + double a[2]; + a[0] = Global::synWave[trackNum][pos0++]; + a[1] = Global::synWave[trackNum][j++]; + +#if 0 + double sigma = StdDeviation(a, 2); + +if (first) +{ +first = false; +// printf("First blip: %.0lf, %.0lf (sigma=%.2lf) [pos=%d, la=%d]\n", a[0], a[1], sigma, i + pos - 100, pos0); + +if (trackNum == 137) +{ + uint32_t lla = LoopLookahead(trackNum, 0, j, &full); + uint32_t llap1 = LoopLookahead(trackNum, 1, j, &full2); + printf("%.2f: pos0=%d, j=%d, sigma=%lf, la=%d%s, la+1=%d%s", (float)trackNum / 4.0f, pos0, j, sigma, lla, (full ? " *equal" : ""), llap1, (full2 ? " *equal" : "")); +} +} +#endif + + // Hmm, not in sync. See if we can re-sync + blips++; + + do + { + if (a[0] < a[1]) + a[0] += Global::synWave[trackNum][pos0++]; + else + a[1] += Global::synWave[trackNum][j++]; + + // Maybe put all the other heuristics in too? :-/ + if ((StdDeviation(a, 2) <= 2.50) + || (j >= Global::synWaveLen[trackNum])) + break; + } + while (true); + } + +#if 0 +if (trackNum == 137) +printf(" blips=%d, la=%d\n", blips, matchCount); +#endif + +//maybe we should keep an array of the analyses so we can decide afterward which one is best... probably not necessary... + if (blips < bestBlips) + { + bestBlips = blips; + bestBlipsPos = pos + i; + } + + if (matchCount > bestMatchCount) + { + bestMatchCount = matchCount; + bestMatchCountPos = pos + i; + } + + // Did we find a perfect lookahead? If so, we're done. +// if (blips == 0) +// break; + } + + // Now we're done trying to fit the loop, and we didn't find a perfect one, so set up the best we found: + end = bestMatchCountPos - 1; +#if 1 +uint32_t possibleCoverage = Global::synWaveLen[trackNum] - pos; +printf("Possible loop point found at position %d (elp%+d, bestMatchCount=%d (out of %d, %.1f%%), startPos=%d, blips=%d, blipsPos=%d, longest stretch=%d, mlsPos=%d)\n----------------------------------------------------------------------\n", end + 1, end + 1 - posSave, bestMatchCount, possibleCoverage, ((float)bestMatchCount / (float)possibleCoverage) * 100.0f, pos, bestBlips, bestBlipsPos, longestStretch, longestStretchPos); +#endif + return false; +} + + /* Using a histogram, we can get an idea of the drift from the ones: diff --git a/src/dsp.h b/src/dsp.h index 030446f..0b3e0f2 100644 --- a/src/dsp.h +++ b/src/dsp.h @@ -4,7 +4,8 @@ #include #include -double StdDeviation(double *, uint32_t, double * mean = NULL); +double StdDeviation(double *, uint32_t, double * pMean = NULL); +double StdDeviationWave(uint32_t * sync, uint32_t num, double * pMean = NULL); double Largest(double *, uint32_t); uint32_t Largest(uint32_t *, uint32_t); uint32_t LargestIndex(double *, uint32_t); @@ -13,37 +14,25 @@ double Smallest(double *, uint32_t); uint32_t Smallest(uint32_t *, uint32_t); uint32_t SmallestIndex(double *, uint32_t); uint32_t SmallestIndex(uint32_t *, uint32_t); +bool Equal(uint32_t * a1, uint32_t * a2, uint32_t num); +uint32_t IndexForTime(uint32_t trackNum, uint32_t time); -#if 0 -uint32_t Synthesize(uint32_t * sync, uint32_t num, uint32_t * wave, float * amp); -bool FindSync(uint32_t, uint32_t, uint32_t &, uint32_t &); -void FindSyncForStreams(uint32_t * sync, uint32_t num); -void FindInitialSyncForStreams(uint32_t * sync, uint32_t num); -void BacktrackInitialSync(uint32_t * sync, uint32_t num); -void BacktrackInitialSync2(uint32_t * sync, uint32_t num); -void BacktrackInitialSync3(uint32_t * sync, uint32_t num); -void BacktrackInitialSync4(uint32_t * sync, uint32_t num); -void StepBackUntilBad(uint32_t * sync, double * a, uint32_t num); -bool StepBackThruBad(uint32_t * sync, double * a, uint32_t num); -void StepBack(uint32_t * sync, double * a, uint32_t num); -void StepAndAddBack(uint32_t * sync, double * a, uint32_t num); -void StepAndAddBack(uint32_t & sync, double & a, uint32_t i); -void StepForward(uint32_t * sync, double * a, uint32_t num); -void StepAndAddForward(uint32_t * sync, double * a, uint32_t num); -void StepAndAddForward(uint32_t & sync, double & a, uint32_t i); -uint32_t Lookahead(uint32_t * sync, uint32_t num, int32_t dir = 1); -int Resync(uint32_t * sync, double * a, uint32_t num, int32_t dir = 1); -#endif +uint32_t LookaheadWave(uint32_t * passedInSync, uint32_t num, int8_t dir = 1, bool * perfect = NULL); +uint32_t FindSyncBetweenFirstTwo(uint32_t * sync); void FindInitialSyncForStreams2(uint32_t * sync, uint32_t num); uint32_t Synthesize2(uint32_t * sync, uint32_t num, uint32_t * wave, float * amp); - +bool ResyncWave(uint32_t * sync, uint32_t num, int8_t dir = 1); bool AttemptToFindStart(uint32_t * sync, uint32_t num); bool InitialSync(uint32_t * sync, uint32_t num); +uint32_t LoopLookahead(uint32_t trackNum, uint32_t start, uint32_t loopPoint, bool * test = NULL); void SynthesizeTrack(uint32_t trackNum); +//void MakeLoop(uint32_t trackNum); +//uint32_t FindLoopPoint(uint32_t trackNum); +bool FindLoopPoint(uint32_t trackNum, uint32_t & start, uint32_t & end); + // Exported variables extern uint32_t sNum[]; -//extern double ratio[]; extern double initSyncTime[]; #endif // __DSP_H__ diff --git a/src/fileio.cpp b/src/fileio.cpp index a70b4ca..c3718c3 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -10,6 +10,8 @@ #include "fileio.h" #include #include +#include +#include "global.h" static uint32_t crcTable[256] = @@ -78,3 +80,212 @@ uint8_t * ReadFile(const char * filename, uint32_t * size) return buffer; } + +bool LoadA2R(const char * filename) +{ +/* +Really, this crap should go into fileio.cpp. !!! FIX !!! +*/ + static uint8_t a2rHdr[8] = { 0x41, 0x32, 0x52, 0x32, 0xFF, 0x0A, 0x0D, 0x0A }; + static uint8_t a2rHdr1[8] = { 0x41, 0x32, 0x52, 0x31, 0xFF, 0x0A, 0x0D, 0x0A }; + + if (Global::a2r != NULL) + free(Global::a2r); + + Global::a2r = (A2R *)ReadFile(filename, &Global::a2rSize); + + if (Global::a2r == NULL) + return false; + + // Sanity check, to see if what we asked for is what we got + if (memcmp(Global::a2r->magic1, a2rHdr, 8) != 0) + { + // It's not a v2 A2R file, maybe it's v1? + if (memcmp(Global::a2r->magic1, a2rHdr1, 8) == 0) + { + // Bytes 8-F are usually: 01 00 8D 00 A5 01 00 00 + // First, allocate mem to copy the old version to the new: + uint8_t * oldfile = (uint8_t *)Global::a2r; + uint8_t * newfile = (uint8_t *)malloc(Global::a2rSize + 36); + memcpy(newfile + 52, oldfile + 16, Global::a2rSize - 16); + + // Make sure creator is set correctly (v1 doesn't have it) + memset(Global::a2r->creator, 0x20, 32); + + // Swap in the new file, free the old one + free(Global::a2r); + Global::a2r = (A2R *)newfile; + Global::a2rSize += 36; // Add in the size of the INFO chunk + + // Fix up stuff that's different between v1 and v2 +//printf("A2R Size: %08X\n", Global::a2rSize); +//printf("A2R Stream Size: %08X (preswap)\n", Global::a2r->strmSize); + SwapBytes32((uint8_t *)&Global::a2r->strmSize); +//printf("A2R Stream Size: %08X (postswap)\n", Global::a2r->strmSize); + uint32_t dataSize = Uint32LE(Global::a2r->strmSize); + uint32_t pos = 0; + + while (pos < dataSize) + { + A2RStream * stream = (A2RStream *)(&Global::a2r->data[pos]); + + if (stream->location == 0xFF) + break; + + SwapBytes32(stream->dataLength); + SwapBytes32(stream->estLoopPoint); + pos += 10 + Uint32LE(stream->dataLength); + } + + // Change INFO to META & fix size (if any, dunno if it's optional) + if (Global::a2rSize > (60 + dataSize)) + { + memcpy(&Global::a2r->data[dataSize], "META", 4); + SwapBytes32(&Global::a2r->data[dataSize + 4]); + } + } + else + { + free(Global::a2r); + Global::a2r = NULL; + +// QMessageBox::critical(this, "Bad A2R file", "It may have an .a2r extension, but it isn't a valid A2R file."); + + return false; + } + } + + // Setup individual stream pointers + Global::numStreams = 0; + uint8_t * streamPtr = Global::a2r->data; + + while ((*streamPtr != 0xFF) && (Global::numStreams < 800)) + { + Global::stream[Global::numStreams] = (A2RStream *)streamPtr; + streamPtr += 10 + Uint32LE(Global::stream[Global::numStreams]->dataLength); + Global::numStreams++; + } + + // Metadata check + Global::metadata = NULL; + + if (Global::a2rSize > (60 + Uint32LE(Global::a2r->strmSize))) + { + Global::metadata = (A2RMetadata *)((uint8_t *)Global::a2r + (60 + Uint32LE(Global::a2r->strmSize))); + + // Make sure it's plausible metadata + if (memcmp(Global::metadata->metaTag, "META", 4) != 0) + Global::metadata = NULL; + } + + // Unpack TMNG & XTMG streams to simplify analysis + for(uint32_t i=0; icaptureType == 2) + continue; + + // We skip the first timing byte because it can't tell you what the actual time was when the pulse was seen--it's the time between when the *capture* started and the pulse was seen, not the time between the previous pulse and this one! So that first one is discarded since it's worse than useless; it's misleading. + for(uint32_t j=1; jdataLength); j++) + { + uint32_t a = Global::stream[i]->data[j]; + + while ((Global::stream[i]->data[j] == 0xFF) || (a < 24)) + { + j++; + a += Global::stream[i]->data[j]; + } + + Global::wave[i][Global::waveLen[i]] = a; + Global::waveLen[i]++; + } + } + +//ISO-8061 date format +#if 0 + char buf[200]; + time_t t = time(NULL); + tm * tmp = gmtime(&t); + strftime(buf, sizeof(buf), "%FT%TZ", tmp); + printf("Time is: %s\n", buf); +#endif + + return true; +} + + +bool WriteWOZFile(const char * filename) +{ + // See if we can actually write a file; if not, there's no need to check + // anything else + FILE * file = fopen(filename, "wb"); + + if (!file) + return false; + + // Need to come up with proper numbers here... + uint32_t numTrackBlocks = 0; + + for(uint32_t i=0; i<141; i++) + numTrackBlocks += (Global::bStreamLen[i] + 511) / 512; + + uint32_t wozSize = sizeof(WOZ2) + (numTrackBlocks * 512) + (Global::metadata != NULL ? Global::metadata->metaSize + 8 : 0); + + WOZ2 * woz = (WOZ2 *)malloc(wozSize); + + memcpy(woz->magic1, "WOZ2\xFF\x0A\x0D\x0A", 8); + + memcpy(woz->infoTag, "INFO", 4); + woz->infoSize = Uint32LE(60); + woz->infoVersion = 1; + woz->diskType = 1; + woz->writeProtected = 1; + woz->synchronized = 1; + woz->cleaned = 1; + memcpy(woz->creator, "WOZ Maker v1.0.0 ", 32); + woz->diskSides = 1; + woz->bootSectorFmt = 1; + woz->optimalBitTmg = 32; + woz->compatibleHW = Uint16LE(0); + woz->requiredRAM = Uint16LE(0); + + memcpy(woz->tmapTag, "TMAP", 4); + woz->tmapSize = Uint32LE(160); + + for(uint32_t i=0; i<141; i++) + woz->tmap[i] = (Global::bStreamLen[i] == 0 ? 0xFF : i); + + memcpy(woz->trksTag, "TRKS", 4); + woz->trksSize = Uint32LE(1280 + (numTrackBlocks * 512)); + uint16_t startBlock = 0, largestBlock = 0; + + for(uint32_t i=0; i<141; i++) + { + uint16_t blockLen = (Global::bStreamLen[i] + 511) / 512; + memset(&woz->data[startBlock * 512], 0, blockLen * 512); + memcpy(&woz->data[startBlock * 512], Global::bStream[i], Global::bStreamLen[i]); + woz->track[i].startingBlock = Uint16LE(startBlock + 3); + woz->track[i].blockCount = Uint16LE(blockLen); + woz->track[i].bitCount = Uint16LE(Global::bStreamLenBits[i]); + startBlock += blockLen; + + if (blockCount > largestBlock) + largestBlock = blockCount; + } + + woz->largestTrack = Uint16LE(largestBlock); + + if (Global::metadata != NULL) + memcpy(&woz->data[startBlock * 512], Global::metadata, Uint32LE(Global::metadata->metaSize) + 8); + + woz->crc32 = Uint32LE(CRC32(&woz->infoTag[0], wozSize - 12)); + fwrite(woz, 1, wozSize, file); + fclose(file); + + free(woz); + + return true; +} + diff --git a/src/fileio.h b/src/fileio.h index 0ee24d2..3b42dbf 100644 --- a/src/fileio.h +++ b/src/fileio.h @@ -92,10 +92,55 @@ struct WOZ WOZTrack track[]; // Variable length array for the track data proper }; +struct WOZTrack2 +{ + uint16_t startingBlock; // 512 byte block # where this track starts (relative to the start of the file) + uint16_t blockCount; // # of blocks in this track + uint32_t bitCount; // # of bits in this track +}; + +struct WOZ2 +{ + // Header + uint8_t magic1[4]; // "WOZ1" + uint8_t magic2[4]; // $FF $0A $0D $0A + uint32_t crc32; // CRC32 of the remaining data in the file + + // INFO chunk + uint8_t infoTag[4]; // "INFO" + uint32_t infoSize; // Always 60 bytes long + uint8_t infoVersion; // Currently 1 + uint8_t diskType; // 1 = 5 1/4", 2 = 3 1/2" + uint8_t writeProtected; // 1 = write protected disk + uint8_t synchronized; // 1 = cross-track sync was used during imaging + uint8_t cleaned; // 1 = fake bits removed from image + uint8_t creator[32]; // Software that made this image, padded with 0x20 + uint8_t diskSides; // 5 1/4" disks always have 1 side (v2 from here on) + uint8_t bootSectorFmt; // 5 1/4" only (0=unknown, 1=16 sector, 2=13 sector, 3=both) + uint8_t optimalBitTmg; // In ticks, standard for 5 1/4" is 32 (4 µs) + uint16_t compatibleHW; // Bitfield showing hardware compatibility (1=][, 2=][+, 4=//e (unenh), 8=//c, 16=//e (enh), 32=IIgs, 64=//c+, 128=///, 256=///+) + uint16_t requiredRAM; // Minimum size in K, 0=unknown + uint16_t largestTrack; // Number of 512 byte blocks used by largest track + uint8_t pad1[14]; // Padding to 60 bytes + + // TMAP chunk + uint8_t tmapTag[4]; // "TMAP" + uint32_t tmapSize; // Always 160 bytes long + uint8_t tmap[160]; // Track map, with empty tracks set to $FF + + // TRKS chunk + uint8_t trksTag[4]; // "TRKS" + uint32_t trksSize; // Varies, depending on # of tracks imaged + WOZTrack2 track[160]; // Actual track info (corresponding to TMAP data) + uint8_t data[]; // Variable length array for the track data proper +}; + // Exported functions uint32_t CRC32(const uint8_t * data, uint32_t length); uint8_t * ReadFile(const char * filename, uint32_t * size); +bool LoadA2R(const char * filename); +bool WriteWOZFile(const char * filename); // Inline functions ("get" functions--need to write "set" functions) diff --git a/src/global.cpp b/src/global.cpp index 52b9fb9..44b18fa 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -43,3 +43,7 @@ uint32_t Global::waveSync = 0; uint32_t Global::synWave[141][80000] = { 0 }; uint32_t Global::synWaveLen[141] = { 0 }; +uint8_t Global::bStream[141][80000] = { 0 }; +uint32_t Global::bStreamLen[141] = { 0 }; +uint32_t Global::bStreamLenBits[141] = { 0 }; + diff --git a/src/global.h b/src/global.h index 1db173d..0921595 100644 --- a/src/global.h +++ b/src/global.h @@ -35,6 +35,9 @@ class Global static uint32_t waveSync; static uint32_t synWave[141][80000]; // Synthesized wave static uint32_t synWaveLen[141]; // Synthesized wave length + static uint8_t bStream[141][80000]; + static uint32_t bStreamLen[141]; + static uint32_t bStreamLenBits[141]; }; #endif // __GLOBAL_H__ diff --git a/src/mainwin.cpp b/src/mainwin.cpp index 528924d..e98031d 100644 --- a/src/mainwin.cpp +++ b/src/mainwin.cpp @@ -181,8 +181,11 @@ void MainWin::HandleLoadFile(void) lastDir = QFileInfo(filename).path(); - if (!LoadA2R(filename)) + if (!LoadA2R(filename.toUtf8().data())) + { + QMessageBox::critical(this, "Bad A2R file", "It may have an .a2r extension, but it isn't a valid A2R file."); return; + } Global::trackNum = 0; mainWidget->wfWidget->HandleUpdate(); @@ -200,6 +203,7 @@ void MainWin::AboutWozMaker(void) } +#if 0 bool MainWin::LoadA2R(const QString filename) { /* @@ -333,4 +337,5 @@ Really, this crap should go into fileio.cpp. !!! FIX !!! return true; } +#endif diff --git a/src/mainwin.h b/src/mainwin.h index 3b81ab2..b3edaaa 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -29,7 +29,7 @@ class MainWin: public QMainWindow void HandleLoadFile(void); void AboutWozMaker(void); - bool LoadA2R(const QString); +// bool LoadA2R(const QString); private: MainWidget * mainWidget; diff --git a/src/waveformwidget.cpp b/src/waveformwidget.cpp index e3ca3bf..5368a8b 100644 --- a/src/waveformwidget.cpp +++ b/src/waveformwidget.cpp @@ -14,7 +14,7 @@ // Local variables -static uint32_t slip[9]; +static uint32_t slip[6]; static bool foundBad = false; @@ -72,6 +72,7 @@ void WaveformWidget::HandleUpdate(void) Global::swLen = 0; +// !!! FIX !!! Need to take this out so it uses the already synthesized stuff done in the parallel thread... if (Global::streamCount > 1) { // Try aligning streams algorithmically... @@ -560,7 +561,7 @@ x positions are 16 pix apart, ideally. So to get the # of bits, we need to divi char buf[10]; - if ((i % 100) == 0) + if ((i % 10) == 0) { sprintf(buf, "|%d", i + 1); painter.setPen(whitePen);