📄 ocwav.c
字号:
/*------------------------------------------------------------------------------*
* File Name: *
* Creation: *
* Purpose: OriginC Source C file *
* Copyright (c) ABCD Corp. 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 *
* All Rights Reserved *
* *
* Modification Log: *
*------------------------------------------------------------------------------*/
////////////////////////////////////////////////////////////////////////////////////
#include <origin.h>
#include "ocWAV.h"
#include "local.h"
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
// Read a WAV file
int ocWAVReadFile(string strFileName, string strWorksheetName)
{
file fid;
int iStatus = 0;
int iFileSize = 0;
int iBytesRead = 0;
int iResult = 0;
int iFmtRead = 0;
int iPos = 0;
// fmt info
FORMATCHUNK fmt; // struct defined in header
unsigned int iDataSize;
unsigned int iSamples;
string strTemp;
int iChunkSize = 0;
char cChunkName[9];
if( fid.Open(strFileName, file::shareDenyNone) ) // fid.Open(strFileName, file::modeRead)
{
// What size is the file?
iFileSize = fid.SeekToEnd();
// Rewind
fid.SeekToBegin();
// First chunk name is RIFF.
iBytesRead = fid.Read(&cChunkName,4);
cChunkName[4] = 0;
strTemp = cChunkName;
if(strTemp.Compare("RIFF"))
{
iStatus = 2;
printf( OCWAV_NOTWAV ); // "Not a WAV file.\n"
fid.Close(); // Not needed, but clean
return iStatus;
}
// File size should be consistent with description.
iBytesRead = fid.Read(&iChunkSize,4);
if(iChunkSize + 8 > iFileSize)
{
iStatus = 3;
printf( OCWAV_NOTGOOD ); // "File size and description inconsistent.\n"
fid.Close(); // Not needed, but clean
return iStatus;
}
// Should be a WAVE.
iBytesRead = fid.Read(&cChunkName,4);
cChunkName[4] = 0;
strTemp = cChunkName;
if(strTemp.Compare("WAVE"))
{
iStatus = 4;
printf( OCWAV_NOTWAV) ;
fid.Close(); // Not needed, but clean
return iStatus;
}
// Should be a good WAV file. Still need to verify that it's PCM encoded
// Many chunk types. Only process "fmt " and "data" (in that order).
iPos = fid.GetPosition();
while (iPos < iFileSize)
{
iBytesRead = fid.Read(&cChunkName,4);
cChunkName[4] = 0;
strTemp = cChunkName;
iBytesRead = fid.Read(&iChunkSize,4);
if(!strTemp.Compare("fmt "))
{
if(iFmtRead == 0)
{
iFmtRead = 1;
// printf("Reading fmt ...\n");
iBytesRead = fid.Read(&fmt, sizeof(fmt));
if(fmt.iWAVFormat != 1)
{
iStatus = 7;
printf( OCWAV_PCMONLY ); // "Only PCM formatting supported.\n"
fid.Close(); // Not needed, but clean
return iStatus;
}
Page pp(strWorksheetName);
pp.Info.Add("WAVE");
pp.Info.WAVE.AddSection("fmt");
pp.Info.WAVE.fmt.AddInt("Channels",fmt.iWAVChannels);
pp.Info.WAVE.fmt.AddInt("Frequency", fmt.iWAVFrequency);
pp.Info.WAVE.fmt.AddInt("BitsPerSample", fmt.iWAVBitsPerSample);
}
else
{
iStatus = 5;
printf( OCWAV_ONEFMT ); // "Duplicate fmt chunk not allowed.\n"
fid.Close(); // Not needed, but clean
return iStatus;
}
// printf("%s : CHAN %u, FREQ %u, BiPS %u\n",strFileName, fmt.iWAVChannels, fmt.iWAVFrequency, fmt.iWAVBitsPerSample);
}
if(!strTemp.Compare("data"))
{
if(iFmtRead == 1)
{
// printf("Reading data ...\n");
// Setup worksheet with correct columns
Worksheet wks(strWorksheetName);
// Remove existing columns
int iNumCols = wks.GetNumCols();
while(iNumCols > 0)
{
wks.DeleteCol(0);
iNumCols = wks.GetNumCols();
}
wks.AddCol();
wks.Columns(0).SetLabel("Time");
if(fmt.iWAVChannels == 1)
{
wks.AddCol();
wks.Columns(1).SetLabel("Data");
}
else
{
wks.AddCol();
wks.Columns(1).SetLabel("Left");
}
if(fmt.iWAVChannels == 2)
{
wks.AddCol();
wks.Columns(2).SetLabel("Right");
}
wks.ShowLabels();
// Attach to columns, calculate sample and data sizes
Dataset dsTime(strWorksheetName, 0);
wks.Columns(0).SetType(OKDATAOBJ_DESIGNATION_X);
Dataset dsLeft(strWorksheetName, 1);
iDataSize = fmt.iWAVBitsPerSample / 8;
iSamples = iChunkSize / (fmt.iWAVChannels * iDataSize);
double dSeconds = (double) iSamples / (double) fmt.iWAVFrequency;
Page pp(strWorksheetName);
pp.Info.WAVE.fmt.AddInt("Samples", iSamples);
pp.Info.WAVE.fmt.AddDouble("Seconds", dSeconds);
// Fill Time column - Using OriginC equivalent of data(min,max,inc)
dsTime.Data((double) 1 / fmt.iWAVFrequency, (double) iSamples / fmt.iWAVFrequency, (double) 1 / fmt.iWAVFrequency);
// Read data
switch(fmt.iWAVBitsPerSample)
{
case 8:
vector<unsigned char> tempdata;
tempdata.SetSize(iChunkSize);
fid.Read(tempdata, iChunkSize);
dsLeft = tempdata;
break;
case 16:
vector<short> tempdata;
tempdata.SetSize(iChunkSize / 2);
fid.Read(tempdata, iChunkSize);
dsLeft = tempdata;
break;
default:
iStatus = 8;
printf( OCWAV_BITSIZE ); // "Unsupported bit size.\n"
fid.Close(); // Not needed, but clean
return iStatus;
}
// Split stereo data into two channels - LabTalk
if(fmt.iWAVChannels == 2)
LT_execute("wo -a 1;get col(2) -e last;copy -u col(2) col(4) col(3);copy col(4) col(2);del col(4);set %H -er last/2;");
}
else
{
iStatus = 6;
printf( OCWAV_FMTORDER ); // "fmt chunk must precede data chunk.\n"
fid.Close(); // Not needed, but clean
return iStatus;
}
}
if(!strTemp.Compare("LIST"))
{
iBytesRead = fid.Read(&cChunkName,4);
cChunkName[4] = 0;
strTemp = cChunkName;
// I only handle LISTINFO chunks
if(!strTemp.Compare("INFO"))
{
string strTemp2;
Page pp(strWorksheetName);
pp.Info.WAVE.AddSection("LIST");
pp.Info.WAVE.LIST.AddSection("INFO");
int iChunkBytesRead = 4;
}
}
// Position to next Chunk
fid.Seek(iPos + 8 + iChunkSize, file::begin);
iPos = fid.GetPosition();
// Align on 16 bit boundary
if(iPos&1) fid.Seek(1, file::current);
// Reset cChunkName
cChunkName[0] = 0;
}
fid.Close();
}
else
{
iStatus = 1;
printf( OCWAV_OPENFAIL , strFileName); // "Failed to open file %s.\n"
fid.Close(); // Not needed, but clean
}
LT_set_str("%N",strFileName);
LT_execute("page.label $= %N; page.title = 3;");
return iStatus;
}
// Write a WAV file
// This function expects appropriate info storage for a WAV file
// The ocWAVAnalyzeData function can setup this storage
int ocWAVWriteFile(string strFilename, string strWorksheetName, int iColL, int iColR, double dFreqMult = 1, double dAmpMult = 1)
{
file fid;
int iStatus = 0;
FORMATCHUNK sFormat;
int iCol = 0;
int iChannels = 1;
int iFrequency = 0;
int iBits = 0;
int iSamples = 0;
int iBytes = 0;
int iTemp = 0;
// Stereo or Mono?
iColL -= 1; // OriginC columns are indexed from zero, function written as one-based
iColR -= 1; // OriginC columns are indexed from zero, function written as one-based
if(iColL != iColR) iChannels = 2;
// Frequency and data format
string strTemp;
double dValue;
strTemp = "value = " + strWorksheetName + "!page.info.wave.fmt.frequency";
LT_execute(strTemp);
LT_get_var("value",&dValue);
iFrequency = (int) dValue;
strTemp = "value = " + strWorksheetName + "!page.info.wave.fmt.bitspersample";
LT_execute(strTemp);
LT_get_var("value",&dValue);
iBits = (int) dValue;
// If Frequency and Bits are missing then derive them
if(iFrequency == 0 || iBits == 0)
{
Dataset ds(strWorksheetName,1);
string strDatasetName;
int iResult;
ds.GetName(strDatasetName);
iResult = ocWAVAnalyzeData(strDatasetName);
if(iResult)
{
iFrequency = 8000;
iBits = 16;
}
}
// Multiply by Frequency factor
iFrequency = (int)(iFrequency * dFreqMult);
if( fid.Open(strFilename, file::modeCreate + file::modeReadWrite ) )
{
sFormat.iWAVFormat = 1;
sFormat.iWAVChannels = iChannels;
sFormat.iWAVFrequency = iFrequency;
sFormat.iWAVAlign = iChannels * iBits / 8;
sFormat.iWAVBytesPerSecond = iFrequency * sFormat.iWAVAlign;
sFormat.iWAVBitsPerSample = iBits;
// Get size of data - based on Left Channel
Worksheet wks(strWorksheetName);
iBytes = iBits / 8;
Dataset ds1(wks, iColL);
iSamples = ds1.GetUpperBound();
// Need one or the other - just create both
vector<short> vChan16;
vector<unsigned char> vChan8;
// Combine Left and Right Channels (interleaved)
iCol = iColL;
if(iColL != iColR)
{
LT_set_var("col1", iColL + 1);
LT_set_var("col2", iColR + 1);
LT_execute("wo -a 1;copy -z wcol(col1) wcol(col2) wcol(wks.ncols);");
iSamples *= 2;
iCol = wks.GetNumCols() - 1;
}
// Copy datasets to vectors
Dataset ds(wks, iCol);
if(iBytes == 1)
{
vChan8 = ds;
vChan8 = (vChan8 - 128) * dAmpMult + 128;
}
else
{
vChan16 = ds;
vChan16 = vChan16 * dAmpMult;
iSamples *= 2;
}
// Now we can write the file
fid.Write("RIFF", 4);
// Calculate final file size - 8 and write to file (see comments below)
iTemp = 84 + iSamples;
fid.Write(&iTemp, sizeof(iTemp));
// Always a WAVE file - ADD 4 BYTES
fid.Write("WAVE", 4);
// fmt chunk - ADD 4 BYTES
fid.Write("fmt ", 4);
// fmt chunk size - ADD 4 BYTES
iTemp = 16;
fid.Write(&iTemp, sizeof(iTemp));
// fmt chunk data - ADD 16 BYTES
fid.Write(&sFormat, sizeof(sFormat));
// data chunk - ADD 4 BYTES
fid.Write("data", 4);
// data chunk size - ADD 4 BYTES
fid.Write(&iSamples,sizeof(iSamples));
// data chunk data - ADD iSamples BYTES
if(iBytes == 1)
fid.Write(vChan8, iSamples);
else
fid.Write(vChan16, iSamples);
// Our stamp chunk - ADD 4 BYTES
fid.Write("LIST",4);
// Chunk size - ADD 4 BYTES
iTemp = 24;
fid.Write(&iTemp, sizeof(iTemp));
// Chunk data - ADD 40 BYTES
fid.Write("INFOISFT",8);
iTemp = 16;
fid.Write(&iTemp, sizeof(iTemp));
fid.Write("Modified by Origin software.",28);
if(iColL != iColR)
LT_execute("del wcol(wks.ncols);");
fid.Flush();
fid.Close();
}
else
{
iStatus = 1;
printf( OCWAV_OPENFAIL ); // "Failed to open file %s.\n"
}
// printf("Done.\n");
return iStatus;
}
// Play a WAV file
// The default method is to use mci command strings
// If this method fails, an alternate is provided to use the Windows SNDREC32.EXE program
void ocWAVPlayFile(string strFileName, int iMethod = 0)
{
int iReturn = 0;
if(iMethod)
{
LT_set_str("%Z",strFileName);
LT_execute("run -e sndrec32.exe /play /close %Z;");
}
else
{
string strTemp = "open ";
strTemp += strFileName;
iReturn = mciSendString(strTemp, "", 0, 0);
strTemp = "play ";
strTemp += strFileName;
strTemp += " wait";
iReturn = mciSendString(strTemp, "", 0, 0);
strTemp = "close all ";
iReturn = mciSendString(strTemp, "", 0, 0);
}
}
// Listen to a dataset
// If the Info storage for WAVE exists, then use it
void ocWAVPlayData(string strDatasetName, double dFreqMult = 1, double AmpMult = 1)
{
int iResult;
iResult = ocWAVAnalyzeData(strDatasetName);
printf("Returned %u from analysis.\n",iResult);
}
int ocWAVAnalyzeData(string strDasetName1, string strDatasetName2)
{
printf("Executing the overloaded two strings version.\n");
return 0;
}
// Analyze a Dataset for export to WAV file
// Create the appropriate info storage
int ocWAVAnalyzeData(string strDatasetName)
{
printf("This function not available yet.\n");
return 1;
}
// The filter function version
int ImportWAV(Page& pgTarget, TreeNode& trFilter, LPCSTR lpcszFile, int nFile)
{
string strName;
if(pgTarget.GetType() == EXIST_WKS)
{
pgTarget.GetName(strName);
}
else
{
WorksheetPage pg;
pg.Create("origin.otp");
pg.GetName(strName);
}
LT_set_str("%B",strName);
LT_execute("win -a %B;");
return ocWAVReadFile(lpcszFile, strName);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -