//----------------------------------------------------------------------------- // Makes a single frame of spheremap //----------------------------------------------------------------------------- void CVTFTexture::ComputeSpheremapFrame( unsigned char **ppCubeFaces, unsigned char *pSpheremap, LookDir_t lookDir ) { SphereCalc_t sphere; CalcInit( &sphere, m_nWidth, ppCubeFaces, lookDir ); int offset = 0; for ( int y = 0; y < m_nHeight; y++ ) { for ( int x = 0; x < m_nWidth; x++ ) { int r = 0, g = 0, b = 0, a = 0; float u = (float)x - m_nWidth * 0.5f; float v = m_nHeight * 0.5f - (float)y; CalcSphereColor( &sphere, u, v ); r += sphere.m_pColor[0]; g += sphere.m_pColor[1]; b += sphere.m_pColor[2]; a += sphere.m_pColor[3]; CalcSphereColor( &sphere, u + 0.25, v ); r += sphere.m_pColor[0]; g += sphere.m_pColor[1]; b += sphere.m_pColor[2]; a += sphere.m_pColor[3]; v += 0.25; CalcSphereColor( &sphere, u + 0.25, v ); r += sphere.m_pColor[0]; g += sphere.m_pColor[1]; b += sphere.m_pColor[2]; a += sphere.m_pColor[3]; CalcSphereColor( &sphere, u, v ); r += sphere.m_pColor[0]; g += sphere.m_pColor[1]; b += sphere.m_pColor[2]; a += sphere.m_pColor[3]; pSpheremap[ offset + 0 ] = r >> 2; pSpheremap[ offset + 1 ] = g >> 2; pSpheremap[ offset + 2 ] = b >> 2; pSpheremap[ offset + 3 ] = a >> 2; offset += 4; } } }
int OmConvertRunConvert(omconvert_settings_t *settings, calc_t *calc) { int retVal = EXIT_OK; omdata_t omdata = { 0 }; om_convert_arrangement_t arrangement = { 0 }; // Output information file FILE *infofp = NULL; if (settings->infoFilename != NULL) { infofp = fopen(settings->infoFilename, "wt"); if (infofp == NULL) { fprintf(stderr, "ERROR: Cannot open output information file: %s\n", settings->infoFilename); return EXIT_CANTCREAT; } } // Load input data if (!OmDataLoad(&omdata, settings->filename)) { const char *msg = "ERROR: Problem loading file.\n"; fprintf(stderr, msg); fprintf(stdout, msg); return EXIT_DATAERR; } fprintf(stderr, "Data loaded!\n"); OmDataDump(&omdata); // For each session: omdata_session_t *session; int sessionCount = 0; for (session = omdata.firstSession; session != NULL; session = session->sessionNext) { sessionCount++; fprintf(stderr, "=== SESSION %d ===\n", sessionCount); if (sessionCount > 1) { fprintf(stderr, "NOTE: Skipping session %d...\n", sessionCount); continue; } // Find a configuration OmConvertFindArrangement(&arrangement, settings, &omdata, session, defaultChannelPriority); // Calibration configuration omcalibrate_config_t calibrateConfig = { 0 }; OmCalibrateConfigInit(&calibrateConfig); calibrateConfig.stationaryTime = settings->stationaryTime; // 10.0; calibrateConfig.stationaryRepeated = settings->repeatedStationary; // Start a player om_convert_player_t player = { 0 }; OmConvertPlayerInitialize(&player, &arrangement, settings->sampleRate, settings->interpolate); // Initialize here for find stationary points // Initialize calibration omcalibrate_calibration_t calibration; OmCalibrateInit(&calibration); if (settings->calibrate) { // Find stationary points omcalibrate_stationary_points_t *stationaryPoints; fprintf(stderr, "Finding stationary points...\n"); stationaryPoints = OmCalibrateFindStationaryPoints(&calibrateConfig, &player); // Player already initialized fprintf(stderr, "Found stationary points: %d\n", stationaryPoints->numValues); // Dump no calibration OmCalibrateDump(&calibration, stationaryPoints, 0); // Auto-calibrate fprintf(stderr, "Auto-calibrating...\n"); int calibrationResult = OmCalibrateFindAutoCalibration(&calibrateConfig, stationaryPoints, &calibration); OmCalibrateDump(&calibration, stationaryPoints, 1); if (calibrationResult < 0) { fprintf(stderr, "Auto-calibration: using identity calibration...\n"); int ec = calibration.errorCode; // Copy error code int na = calibration.numAxes; // ...and num-axes OmCalibrateInit(&calibration); calibration.errorCode = ec; // Copy error code to identity calibration calibration.numAxes = na; // ...and num-axes } // Free stationary points OmCalibrateFreeStationaryPoints(stationaryPoints); } // Output range scalings int outputAccelRange = 8; // TODO: Possibly allow for +/- 16 outputs (currently always +/-8g -> 16-bit signed)? if (outputAccelRange < 8) { outputAccelRange = 8; } // Minimum of +/-2, +/-4, +/-8 all get output coded as +/-8 int outputAccelScale = 65536 / (2 * outputAccelRange); int outputChannels = arrangement.numChannels + 1; int outputRate = (int)(player.sampleRate + 0.5); int outputSamples = player.numSamples; // Metadata - [Artist�"IART" WAV chunk] Data about the device that made the recording char artist[WAV_META_LENGTH] = { 0 }; sprintf(artist, "Id: %u\n" "Device: %s\n" "Revision: %d\n" "Firmware: %d", omdata.metadata.deviceId, omdata.metadata.deviceTypeString, omdata.metadata.deviceVersion, omdata.metadata.firmwareVer ); // Metadata - [Title�"INAM" WAV chunk] Data about the recording configuration char name[WAV_META_LENGTH] = { 0 }; sprintf(name, "Session: %u\n" "Start: %s\n" "Stop: %s\n" "Config-A: %d,%d\n" "Metadata: %s", (unsigned int)omdata.metadata.sessionId, TimeString(omdata.metadata.recordingStart), TimeString(omdata.metadata.recordingStop), omdata.metadata.configAccel.frequency, omdata.metadata.configAccel.sensitivity, omdata.metadata.metadata ); // Metadata - [Creation�date�"ICRD"�WAV�chunk] - Specify�the�time of the first sample (also in the comment for Matlab) char datetime[WAV_META_LENGTH] = { 0 }; sprintf(datetime, "%s", TimeString(arrangement.startTime)); // Metadata - [Comment�"ICMT" WAV chunk] Data about this file representation char comment[WAV_META_LENGTH] = { 0 }; sprintf(comment, "Time: %s\n" "Channel-1: Accel-X\n" "Scale-1: %d\n" "Channel-2: Accel-Y\n" "Scale-2: %d\n" "Channel-3: Accel-Z\n" "Scale-3: %d\n" "Channel-4: Aux", TimeString(arrangement.startTime), outputAccelRange, outputAccelRange, outputAccelRange ); // Create output WAV file FILE *ofp = NULL; if (settings->outFilename != NULL && strlen(settings->outFilename) > 0) { fprintf(stderr, "Generating WAV file: %s\n", settings->outFilename); ofp = fopen(settings->outFilename, "wb"); if (ofp == NULL) { fprintf(stderr, "Cannot open output WAV file: %s\n", settings->outFilename); retVal = EXIT_CANTCREAT; break; } WavInfo wavInfo = { 0 }; wavInfo.bytesPerChannel = 2; wavInfo.chans = outputChannels; wavInfo.freq = outputRate; wavInfo.numSamples = outputSamples; wavInfo.infoArtist = artist; wavInfo.infoName = name; wavInfo.infoDate = datetime; wavInfo.infoComment = comment; // Try to start the data at 1k offset (create a dummy 'JUNK' header) wavInfo.offset = 1024; if (WavWrite(&wavInfo, ofp) <= 0) { fprintf(stderr, "ERROR: Problem writing WAV file.\n"); retVal = EXIT_IOERR; break; } } // Re-start the player OmConvertPlayerInitialize(&player, &arrangement, settings->sampleRate, settings->interpolate); int outputOk = CalcInit(calc, player.sampleRate, player.arrangement->startTime); // Whether any processing outputs are used // Calculate each output sample between the start/end time of session if (!outputOk && ofp == NULL) { fprintf(stderr, "ERROR: No output.\n"); retVal = EXIT_CONFIG; break; } else { // Write other information to info file if (infofp != NULL) { fprintf(infofp, ":\n"); fprintf(infofp, "::: Data about the conversion process\n"); fprintf(infofp, "Result-file-version: %d\n", 1); fprintf(infofp, "Convert-version: %d\n", CONVERT_VERSION); fprintf(infofp, "Processed: %s\n", TimeString(TimeNow())); fprintf(infofp, "File-input: %s\n", settings->filename); fprintf(infofp, "File-output: %s\n", settings->outFilename); fprintf(infofp, "Results-output: %s\n", settings->infoFilename); fprintf(infofp, "Auto-calibration: %d\n", settings->calibrate); fprintf(infofp, "Calibration-Result: %d\n", calibration.errorCode); fprintf(infofp, "Calibration: %.10f,%.10f,%.10f,%.10f,%.10f,%.10f,%.10f,%.10f,%.10f,%.10f\n", calibration.scale[0], calibration.scale[1], calibration.scale[2], calibration.offset[0], calibration.offset[1], calibration.offset[2], calibration.tempOffset[0], calibration.tempOffset[1], calibration.tempOffset[2], calibration.referenceTemperature); fprintf(infofp, "Input-sectors-total: %d\n", omdata.statsTotalSectors); fprintf(infofp, "Input-sectors-data: %d\n", omdata.statsDataSectors); fprintf(infofp, "Input-sectors-bad: %d\n", omdata.statsBadSectors); fprintf(infofp, "Output-rate: %d\n", outputRate); fprintf(infofp, "Output-channels: %d\n", outputChannels); fprintf(infofp, "Output-duration: %f\n", (float)outputSamples / outputRate); fprintf(infofp, "Output-samples: %d\n", outputSamples); fprintf(infofp, ":\n"); fprintf(infofp, "::: Data about the device that made the recording\n"); fprintf(infofp, "%s\n", artist); fprintf(infofp, ":\n"); fprintf(infofp, "::: Data about the recording itself\n"); fprintf(infofp, "%s\n", name); fprintf(infofp, ":\n"); fprintf(infofp, "::: Data about this file representation\n"); fprintf(infofp, "%s\n", comment); } signed short values[OMDATA_MAX_CHANNELS + 1]; int sample; for (sample = 0; sample < outputSamples; sample++) { OmConvertPlayerSeek(&player, sample); // Convert to integers int c; double temp = player.temp; char clipped = player.clipped; double accel[OMCALIBRATE_AXES]; for (c = 0; c < player.arrangement->numChannels; c++) { double interpVal = player.values[c]; double v = player.scale[c] * interpVal; // Apply calibration if (c < OMCALIBRATE_AXES) { // Rescaling is: v = (v + offset) * scale + (temp - referenceTemperature) * tempOffset v = (v + calibration.offset[c]) * calibration.scale[c] + (temp - calibration.referenceTemperature) * calibration.tempOffset[c]; } if (c < OMCALIBRATE_AXES) { accel[c] = v; } // Output range scaled double ov = v * outputAccelScale; // Saturate if (ov < -32768.0) { ov = -32768.0; clipped = 1; } if (ov > 32767.0) { ov = 32767.0; clipped = 1; } // Save values[c] = (signed short)(ov); } // Auxilliary channel uint16_t aux = 0; if (!player.valid) { aux |= WAV_AUX_UNAVAILABLE; } if (clipped) { aux |= WAV_AUX_CLIPPING; } int cycle = sample % (int)player.sampleRate; if (cycle == 0) { aux |= WAV_AUX_SENSOR_BATTERY | (player.aux[0] & 0x3ff); } if (cycle == 1) { aux |= WAV_AUX_SENSOR_LIGHT | (player.aux[1] & 0x3ff); } if (cycle == 2) { aux |= WAV_AUX_SENSOR_TEMPERATURE | (player.aux[2] & 0x3ff); } //player.ettings.auxChannel values[player.arrangement->numChannels] = aux; if (!CalcAddValue(calc, accel, 0.0, player.valid ? true : false)) { fprintf(stderr, "ERROR: Problem writing calculations.\n"); retVal = EXIT_IOERR; break; } #if 0 // TEMPORARY: Write SVM (before filtering) to fourth channel double outSvm = svm * 4096.0; if (outSvm < -32768.0) { outSvm = -32768.0; } if (outSvm > 32767.0) { outSvm = 32767.0; } values[player.arrangement->numChannels] = (signed short)outSvm; #endif // Output //for (c = 0; c < numChannels + 1; c++) { printf("%s%d", (c > 0) ? "," : "", values[c]); } //printf("\n"); if (ofp != NULL) { int bytesToWrite = sizeof(int16_t) * (arrangement.numChannels + 1); static unsigned char cache[1024 * 1024]; // TODO: Don't do this - not thread safe static int cachePosition = 0; // ...or this... memcpy(cache + cachePosition, values, bytesToWrite); cachePosition += bytesToWrite; if (cachePosition + bytesToWrite >= sizeof(cache) || sample + 1 >= outputSamples) { if (fwrite(cache, 1, cachePosition, ofp) != cachePosition) { fprintf(stderr, "ERROR: Problem writing output.\n"); retVal = EXIT_IOERR; break; } cachePosition = 0; fprintf(stderr, "."); } } } } if (ofp != NULL) { fclose(ofp); } CalcClose(calc); fprintf(stderr, "\n"); fprintf(stderr, "Finished.\n"); } OmDataFree(&omdata); if (sessionCount < 1) { fprintf(stderr, "ERROR: No sessions to write.\n"); retVal = EXIT_DATAERR; } if (infofp != NULL) { // Write other information to info file fprintf(infofp, ":\n"); fprintf(infofp, "::: Data about the final state\n"); fprintf(infofp, "Exit: %d\n", retVal); fclose(infofp); infofp = NULL; } return retVal; }
int OmConvertRunWav(omconvert_settings_t *settings, calc_t *calc) { int retVal = EXIT_OK; int i; FILE *fp; WavInfo wavInfo = { 0 }; char infoArtist[WAV_META_LENGTH] = { 0 }; char infoName[WAV_META_LENGTH] = { 0 }; char infoComment[WAV_META_LENGTH] = { 0 }; char infoDate[WAV_META_LENGTH] = { 0 }; double scale[10] = { 8.0 / 32768.0, 8.0 / 32768.0, 8.0 / 32768.0 }; // Check config. if (settings->outFilename != NULL) { fprintf(stderr, "ERROR: Cannot output to WAV when input is WAV.\n"); return EXIT_CONFIG; } if (settings->infoFilename != NULL) { fprintf(stderr, "ERROR: Cannot output to info file when input is WAV.\n"); return EXIT_CONFIG; } fp = fopen(settings->filename, "rb"); if (fp == NULL) { fprintf(stderr, "ERROR: Cannot open WAV file.\n"); return EXIT_NOINPUT; } wavInfo.infoArtist = infoArtist; wavInfo.infoName = infoName; wavInfo.infoComment = infoComment; wavInfo.infoDate = infoDate; if (!WavRead(&wavInfo, fp)) { fprintf(stderr, "ERROR: Problem reading WAV file format.\n"); fclose(fp); return EXIT_DATAERR; } if (wavInfo.bytesPerChannel != 2) { fprintf(stderr, "ERROR: WAV file format not supported (%d bytes/channel, expected 2).\n", wavInfo.bytesPerChannel); fclose(fp); return EXIT_DATAERR; } if (wavInfo.chans < 3 || wavInfo.chans > 16) { fprintf(stderr, "ERROR: WAV file format not supported (%d channels, expected at least 3 and no more than 16).\n", wavInfo.chans); fclose(fp); return EXIT_DATAERR; } if (wavInfo.freq < 1 || wavInfo.freq > 48000) { fprintf(stderr, "ERROR: WAV file format not supported (%d frequency).\n", wavInfo.freq); fclose(fp); return EXIT_DATAERR; } // Extract metadata char *line; #define MAX_FIELDS 32 //char *artistLines[MAX_FIELDS]; int numArtistLines = 0; //for (line = strtok(wavInfo.infoArtist, "\n"); line != NULL; line = strtok(NULL, "\n")) { if (numArtistLines < MAX_FIELDS) { artistLines[numArtistLines++] = line; } } //char *nameLines[MAX_FIELDS]; int numNameLines = 0; //for (line = strtok(wavInfo.infoName, "\n"); line != NULL; line = strtok(NULL, "\n")) { if (numNameLines < MAX_FIELDS) { nameLines[numNameLines++] = line; } } char *commentLines[MAX_FIELDS]; int numCommentLines = 0; for (line = strtok(wavInfo.infoComment, "\n"); line != NULL; line = strtok(NULL, "\n")) { if (numCommentLines < MAX_FIELDS) { commentLines[numCommentLines++] = line; } } // Parse headers bool parsedTime = false; bool parsedScale[10] = { 0 }; double startTime = 0; for (i = 0; i < numCommentLines; i++) { if (strncmp(commentLines[i], "Time:", 5) == 0) { startTime = ParseTime(commentLines[i] + 5); fprintf(stderr, "Time: %s\n", TimeString(startTime)); if (startTime > 0) { parsedTime = true; } } else if (strncmp(commentLines[i], "Scale-", 6) == 0 && (commentLines[i][6] >= '1' && commentLines[i][6] <= '9') && commentLines[i][7] == ':') { int chan = commentLines[i][6] - '1'; double val = atof(commentLines[i] + 8); scale[chan] = val / 32768.0; fprintf(stderr, "Scale-%d: %f (scale[%d] = %f)\n", chan + 1, val, chan, scale[chan]); if (scale[chan] > 0) { parsedScale[chan] = true; } } } // Check we parsed the headers we need if (!parsedTime) { fprintf(stderr, "WARNING: Didn't successfully parse a 'Time' header (using zero).\n"); } for (i = 0; i < 3; i++) { if (!parsedScale[i]) { fprintf(stderr, "WARNING: Didn't successfully parse a 'Scale-%d' header (using defaults).\n", i + 1); } } int bufferSamples = wavInfo.freq * 60 * 60; // 1 hour buffer short *buffer = malloc(sizeof(short) * wavInfo.chans * bufferSamples); if (buffer == NULL) { fprintf(stderr, "ERROR: Problem allocating buffer for WAV file (%d samples).\n", bufferSamples); fclose(fp); return EXIT_SOFTWARE; } // Init. CSV/SVM/WTV/PAEE int outputOk = CalcInit(calc, wavInfo.freq, startTime); if (!outputOk) { fprintf(stderr, "ERROR: No outputs.\n"); retVal = EXIT_CONFIG; } else { fprintf(stderr, "Working...\n"); unsigned long samplesOffset = 0; unsigned long samplesRemaining = wavInfo.numSamples; while (!feof(fp)) { long offset = wavInfo.offset + ((sizeof(short) * wavInfo.chans) * samplesOffset); unsigned long samplesToRead = bufferSamples; if (samplesToRead > samplesRemaining) { samplesToRead = samplesRemaining; } if (samplesToRead <= 0) { break; } fseek(fp, offset, SEEK_SET); unsigned long samplesRead = fread(buffer, sizeof(short) * wavInfo.chans, samplesToRead, fp); if (samplesRead <= 0) { break; } samplesOffset += samplesRead; samplesRemaining -= samplesRead; double values[3]; for (i = 0; i < (int)samplesRead; i++) { const short *v = buffer + i * wavInfo.chans; // Auxilliary channel is last channel bool valid = true; if (wavInfo.chans > 3) { uint16_t aux = v[wavInfo.chans - 1]; if (aux & WAV_AUX_UNAVAILABLE) { valid = false; } } // Scaling from metadata values[0] = v[0] * scale[0]; values[1] = v[1] * scale[1]; values[2] = v[2] * scale[2]; if (!CalcAddValue(calc, values, 0.0, valid)) { fprintf(stderr, "ERROR: Problem writing calculations.\n"); retVal = EXIT_IOERR; break; } } } } free(buffer); fclose(fp); CalcClose(calc); return retVal; }