// CreateBasicVoiceAudioDlg.cpp : implementation file // #include "stdafx.h" #include "dicwav.h" #include "CreateBasicVoiceAudioDlg.h" #include "CaptureWaveDialog.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define LEAD_IMPLEMENTATION_CLASS_UID "1.2.840.114257.0.1" #define LEAD_IMPLEMENTATION_VERSION_NAME "LEADTOOLS Demo" #define DEFAULT_TEXT "Press the Browse button to select a file..." static const char szIntro[]= "The DICOM standard states: \"The Basic Voice Audio IOD is the " " specification of a digitized sound that has been acquired or" " created by an audio modality or by an audio acquisition" " function within an imaging modality. A typical use is \"Report Dictation\".\"" "\r\n\r\nSome of the constraints of this IOD include:\r\n\r\n1.The " "value of the Sampling Frequency (003A, 001A) in the Waveform " "Sequence Item shall be 8000.\r\n\r\n2.The value of the Waveform Sample " "Interpretation (5400,1006) in the Waveform Sequence Item shall be " "UB, MB, or AB. \r\n\r\nThis means that when you use this IOD for report " "dictation for example then the \"Samples Per Second (sampling rate)\"" " for the wave stream needs to be 8K, the \"Format Category\" needs " "to be PCM, mu-Law or a-Law and the \"Bits Per Sample (sample size)\" needs to be 8." "\r\n\r\nThis dialog shows how to use the LDicomWaveformGroup:: LoadAudio function " "to insert a wave file into a DICOM file of type Basic Voice Audio."; ///////////////////////////////////////////////////////////////////////////// // CCreateBasicVoiceAudioDlg dialog CCreateBasicVoiceAudioDlg::CCreateBasicVoiceAudioDlg(CWnd* pParent /*=NULL*/) : CDialog(CCreateBasicVoiceAudioDlg::IDD, pParent) { //{{AFX_DATA_INIT(CCreateBasicVoiceAudioDlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT } void CCreateBasicVoiceAudioDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CCreateBasicVoiceAudioDlg) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CCreateBasicVoiceAudioDlg, CDialog) //{{AFX_MSG_MAP(CCreateBasicVoiceAudioDlg) ON_BN_CLICKED(IDC_BROWSEINPUTWAVEFILE, OnBrowseinputwavefile) ON_BN_CLICKED(IDC_BROWSEOUTPUTDICOMFILE, OnBrowseoutputdicomfile) ON_BN_CLICKED(IDC_CONVERT, OnConvert) ON_BN_CLICKED(IDC_BUTTON_CAPTURE_AUDIO, OnButtonCaptureAudio) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CCreateBasicVoiceAudioDlg message handlers BOOL CCreateBasicVoiceAudioDlg::OnInitDialog() { CDialog::OnInitDialog(); m_nInstanceNumber = 0 ; CWnd *pIntroWnd = GetDlgItem(IDC_EDIT_BASICVOICEAUDIOINTRO); if(pIntroWnd) { pIntroWnd->SetWindowText(szIntro); } SetDlgItemText (IDC_EDIT_INPUT_WAVE, DEFAULT_TEXT); SetDlgItemText (IDC_EDIT_OUTPUT_DICOM, DEFAULT_TEXT); return TRUE; } // Get the name of the wave file void CCreateBasicVoiceAudioDlg::OnBrowseinputwavefile() { CString strInFileName; strInFileName.Empty(); GetDlgItemText (IDC_EDIT_INPUT_WAVE, strInFileName); if(strInFileName == DEFAULT_TEXT) { strInFileName.Empty(); } TCHAR szFilters[] =_T ("Wave Files (*.wav)|*.wav|All files (*.*)|*.*||"); CFileDialog dlg (TRUE, NULL, strInFileName,OFN_HIDEREADONLY |OFN_FILEMUSTEXIST, szFilters); if (dlg.DoModal () == IDOK) { SetDlgItemText (IDC_EDIT_INPUT_WAVE, dlg.GetPathName ()); UpdateData(); } } // Get the name of the resulting DICOM file void CCreateBasicVoiceAudioDlg::OnBrowseoutputdicomfile() { CString strOutFileName; strOutFileName.Empty(); GetDlgItemText (IDC_EDIT_OUTPUT_DICOM, strOutFileName); if(strOutFileName == DEFAULT_TEXT) { strOutFileName.Empty(); } TCHAR szFilters[] =_T ("DICOM Files (*.dic;*.dcm)|*.dic;*.dcm|All files (*.*)|*.*||"); CFileDialog dlg (FALSE, NULL, strOutFileName,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, szFilters); if (dlg.DoModal () == IDOK) { SetDlgItemText (IDC_EDIT_OUTPUT_DICOM, dlg.GetPathName ()); UpdateData(); } } void CCreateBasicVoiceAudioDlg::OnConvert() { CString strOutDICOMFileName; CString strInWaveFileName; WIN32_FIND_DATA FindFileData; HANDLE hFind; LDicomDS VoiceAudioDS; GetDlgItemText (IDC_EDIT_INPUT_WAVE, strInWaveFileName); GetDlgItemText (IDC_EDIT_OUTPUT_DICOM, strOutDICOMFileName); // Some sanity checks ! if((strInWaveFileName.GetLength() == 0) || (strInWaveFileName == DEFAULT_TEXT)) { AfxMessageBox("Please enter a valid input file name "); return ; } // Make sure the file exists hFind = FindFirstFile(strInWaveFileName, &FindFileData); if (hFind == INVALID_HANDLE_VALUE) { AfxMessageBox("Please enter a valid input file name "); return ; } else { FindClose(hFind); } if((strOutDICOMFileName.GetLength() == 0) || (strOutDICOMFileName== DEFAULT_TEXT)) { AfxMessageBox("Please enter a valid output file name "); return ; } if(strInWaveFileName == strOutDICOMFileName) { AfxMessageBox("Input and output file names can't be the same!"); return ; } CWaitCursor Wait; // Load the Basic Voice Audio template DICOM file // which we have stored as a resource if(!LoadVoiceAudioTemplate(VoiceAudioDS)) { AfxMessageBox("Could not load the template Data Set!"); return; } // Insert the wave file into the resulting DICOM file if(!InsertWaveStream(VoiceAudioDS, (char * )(LPCSTR)strInWaveFileName)) { return; } // Generate new UIDs for the resulting dataset SetInstanceUIDs(&VoiceAudioDS); // Generate new instance numbers for the resulting dataset SetInstanceNumbers(&VoiceAudioDS,m_nInstanceNumber++); //Set dates and times SetStudyDateAndTime(&VoiceAudioDS); //Fill meta header InsertMetaHeader(&VoiceAudioDS); // Now save the dataset L_UINT16 nRet = VoiceAudioDS.SaveDS((L_CHAR *)(LPCTSTR)strOutDICOMFileName, DS_GROUP_LENGTHS|DS_METAHEADER_PRESENT); if (nRet != DICOM_SUCCESS) { AfxMessageBox("SaveDS Failed !"); return; } else { CString strMsg = "A new basic Voice Audio File was created and saved to:\n"; strMsg+= strOutDICOMFileName; AfxMessageBox(strMsg,MB_ICONINFORMATION); } } L_BOOL CCreateBasicVoiceAudioDlg::LoadVoiceAudioTemplate(LDicomDS &InDS) { InDS.ResetDS(); // Load the template Data set from the resource HRSRC hRsrc = FindResource(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_TEMPLATE_AU), "TEMPLATES"); if (!hRsrc) { return FALSE; } DWORD dwResLen = SizeofResource(AfxGetInstanceHandle(), hRsrc) ; if (dwResLen == 0) { return FALSE; } HGLOBAL hGlobal = LoadResource(AfxGetInstanceHandle(), hRsrc); if (!hGlobal) { return FALSE; } L_CHAR* pszTemplatePS = (L_CHAR*)LockResource(hGlobal); if (!pszTemplatePS) { return FALSE; } // Create the file in the windows TEMP folder L_CHAR szTempPath[MAX_PATH] = "\0"; DWORD dWord = GetTempPath(sizeof(szTempPath), szTempPath); if(dWord == 0) { return FALSE; } L_CHAR* pszFullName = lstrcat(szTempPath, "VoiceAudioTemplate.DIC"); if (!pszFullName) { return FALSE; } HANDLE hFile = CreateFile(pszFullName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { return FALSE; } DWORD dwWritten; if (!WriteFile(hFile, pszTemplatePS, dwResLen, &dwWritten, NULL)) { DeleteFile(pszFullName); return FALSE; } CloseHandle(hFile); // Loading the dataset if (InDS.LoadDS(pszFullName, DS_LOAD_CLOSE) != DICOM_SUCCESS) { return FALSE; } DeleteFile(pszFullName); return TRUE; } L_BOOL CCreateBasicVoiceAudioDlg::InsertWaveStream(LDicomDS &InDS, L_CHAR * pszInputWaveFileName) { LDicomWaveformGroup AudioWaveformGroup; L_UINT32 uNumberOfChannels= 0 ; // Load an audio file into the waveform group. if(AudioWaveformGroup.LoadAudio(pszInputWaveFileName,0) != DICOM_SUCCESS) { AfxMessageBox("Couldn't insert the wave stream into the dataset.", MB_ICONERROR); return FALSE; } // Verify that the frequency is 8K L_UINT uSamplingFrequency = (L_UINT) AudioWaveformGroup.GetSamplingFrequency(); if(uSamplingFrequency != 8000) { AfxMessageBox("The samples per second (sampling rate) for the wave file should be 8KHz.", MB_ICONERROR); return FALSE; } //Set the channel source uNumberOfChannels = AudioWaveformGroup.GetNumberOfChannels(); if(uNumberOfChannels) { LDicomWaveformChannel* pChannel = NULL; DICOMCODESEQUENCEITEM DicomSourceSequenceItem; L_UINT16 uRet; memset(&DicomSourceSequenceItem , 0 , sizeof(DICOMCODESEQUENCEITEM)); DicomSourceSequenceItem.uStructSize = sizeof(DICOMCODESEQUENCEITEM); DicomSourceSequenceItem.pszCodeValue = "110011"; DicomSourceSequenceItem.pszCodingSchemeDesignator = "DCM"; DicomSourceSequenceItem.pszCodingSchemeVersion = "01"; DicomSourceSequenceItem.pszCodeMeaning = "Dictation"; for(L_UINT32 uIndex = 0 ; uIndex < uNumberOfChannels ; uIndex++) { pChannel = AudioWaveformGroup.GetChannel(uIndex); if(pChannel) { uRet = pChannel->SetChannelSource(&DicomSourceSequenceItem); if(uRet != DICOM_SUCCESS) { AfxMessageBox("Couldn't set the channel source", MB_ICONERROR); return FALSE; } } } } // Insert the waveform group into the dataset if(InDS.AddWaveformGroup(&AudioWaveformGroup, 0,ELEMENT_INDEX_MAX) != DICOM_SUCCESS) { AfxMessageBox("Couldn't insert the wave stream into the dataset."); return FALSE; } return TRUE; } //Generate a UID const TCHAR * const CCreateBasicVoiceAudioDlg::CreateGUID() { SYSTEMTIME SystemTime; FILETIME FileTime; GetSystemTime(&SystemTime); SystemTimeToFileTime(&SystemTime,&FileTime); DWORD Tick=GetTickCount(); DWORD HighWord=FileTime.dwHighDateTime+0x146BF4; wsprintf( m_InstanceGUID, TEXT("1.2.840.114257.0.1%010u%05u%05u%05u%05u%05u%05u"), FileTime.dwLowDateTime, LOWORD(HighWord), HIWORD(HighWord |0x10000000), LOWORD(rand()), HIWORD(Tick), LOWORD(Tick), LOWORD(rand())); return m_InstanceGUID ; } void CCreateBasicVoiceAudioDlg:: SetInstanceUIDs(LDicomDS *pDicomDataSet) { pDICOMELEMENT pElement; // Set STUDY INSTANCE UID pElement = pDicomDataSet->FindFirstElement(NULL, TAG_STUDY_INSTANCE_UID, FALSE); if (pElement == NULL) { pElement = pDicomDataSet->InsertElement(NULL, FALSE, TAG_STUDY_INSTANCE_UID, VR_UI, FALSE, 0); } pDicomDataSet->FreeValue(pElement); pDicomDataSet->SetConvertValue(pElement, (char*) CreateGUID(), 1); // Set SERIES INSTANCE UID pElement = pDicomDataSet->FindFirstElement(NULL, TAG_SERIES_INSTANCE_UID, FALSE); if (pElement == NULL) { pElement = pDicomDataSet->InsertElement(NULL, FALSE, TAG_SERIES_INSTANCE_UID, VR_UI, FALSE, 0); } pDicomDataSet->FreeValue(pElement); pDicomDataSet->SetConvertValue(pElement, (char*) CreateGUID(), 1); // Set SOP INSTANCE UID const char * pGUID = CreateGUID(); pElement = pDicomDataSet->FindFirstElement(NULL, TAG_SOP_INSTANCE_UID, FALSE); if (pElement == NULL) { pElement = pDicomDataSet->InsertElement(NULL, FALSE, TAG_SOP_INSTANCE_UID, VR_UI, FALSE, 0); } pDicomDataSet->FreeValue(pElement); pDicomDataSet->SetConvertValue(pElement, (char * )pGUID, 1); // Media Storage SOP Instance UID pElement = pDicomDataSet->FindFirstElement(NULL, TAG_MEDIA_STORAGE_SOP_INSTANCE_UID, FALSE); if (pElement == NULL) { pElement = pDicomDataSet->InsertElement(NULL, FALSE, TAG_MEDIA_STORAGE_SOP_INSTANCE_UID, VR_UI, FALSE, 0); } pDicomDataSet->FreeValue(pElement); pDicomDataSet->SetConvertValue(pElement, (char * )pGUID, 1); } L_VOID CCreateBasicVoiceAudioDlg :: SetInstanceNumbers(LDicomDS *pDicomDataSet, L_INT nInstanceNumber) { pDICOMELEMENT pElement; char szValue[32]; sprintf(szValue, "%d", nInstanceNumber); // Series number pElement = pDicomDataSet->FindFirstElement(NULL, TAG_SERIES_NUMBER, FALSE); if(pElement) { pDicomDataSet->FreeValue(pElement); pDicomDataSet->SetConvertValue(pElement, szValue, 1); } // Instance number pElement = pDicomDataSet->FindFirstElement(NULL, TAG_INSTANCE_NUMBER, FALSE); if(pElement) { pDicomDataSet->FreeValue(pElement); pDicomDataSet->SetConvertValue(pElement, szValue, 1); } // Study ID pElement = pDicomDataSet->FindFirstElement(NULL, TAG_STUDY_ID, FALSE); if(pElement) { pDicomDataSet->FreeValue(pElement); pDicomDataSet->SetConvertValue(pElement, szValue, 1); } sprintf(szValue, "854125%d", nInstanceNumber); // Accession number pElement = pDicomDataSet->FindFirstElement(NULL, TAG_ACCESSION_NUMBER, FALSE); if(pElement) { pDicomDataSet->FreeValue(pElement); pDicomDataSet->SetConvertValue(pElement, szValue, 1); } } void CCreateBasicVoiceAudioDlg:: SetStudyDateAndTime(LDicomDS *pDicomDataSet) { SYSTEMTIME Time; char szValue[64]; char szDateTime[64]; pDICOMELEMENT pElement; GetLocalTime(&Time); // Set study date pElement = pDicomDataSet->FindFirstElement(NULL, TAG_STUDY_DATE, FALSE); if (pElement) { sprintf(szValue, "%02d/%02d/%04d", Time.wMonth, Time.wDay, Time.wYear); pDicomDataSet->FreeValue(pElement); pDicomDataSet->SetConvertValue(pElement, szValue, 1); } // Set content date pElement = pDicomDataSet->FindFirstElement(NULL, TAG_CONTENT_DATE, FALSE); if (pElement) { pDicomDataSet->FreeValue(pElement); pDicomDataSet->SetConvertValue(pElement, szValue, 1); } // Set study time pElement = pDicomDataSet->FindFirstElement(NULL, TAG_STUDY_TIME, FALSE); if (pElement) { sprintf(szValue, "%02d:%02d:%04d.0", Time.wHour, Time.wMinute, Time.wSecond); pDicomDataSet->FreeValue(pElement); pDicomDataSet->SetConvertValue(pElement, szValue, 1); } sprintf(szDateTime, "%02d/%02d/%04d %02d:%02d:%04d.0+0",Time.wMonth, Time.wDay, Time.wYear, Time.wHour, Time.wMinute, Time.wSecond); // Set content time pElement = pDicomDataSet->FindFirstElement(NULL, TAG_CONTENT_TIME, FALSE); if (pElement) { pDicomDataSet->FreeValue(pElement); pDicomDataSet->SetConvertValue(pElement, szValue, 1); } // Set acquisition date time pElement = pDicomDataSet->FindFirstElement(NULL, TAG_ACQUISITION_DATETIME, FALSE); if (pElement) { pDicomDataSet->FreeValue(pElement); pDicomDataSet->SetConvertValue(pElement, szDateTime, 1); } } L_VOID CCreateBasicVoiceAudioDlg::InsertMetaHeader(LDicomDS *pDS) { pDICOMELEMENT pElement; // Add File Meta Information Version pElement = pDS->FindFirstElement(NULL, TAG_FILE_META_INFORMATION_VERSION, FALSE); if (pElement == NULL) { pElement = pDS->InsertElement(NULL, FALSE, TAG_FILE_META_INFORMATION_VERSION, VR_OB, FALSE, 0); } if(pElement) { L_CHAR cValue[2] = {0x00, 0x01}; pDS->SetCharValue(pElement, cValue, 2); } // Implementation Class UID pElement = pDS->FindFirstElement(NULL, TAG_IMPLEMENTATION_CLASS_UID, FALSE); if (pElement == NULL) { pElement = pDS->InsertElement(NULL, FALSE, TAG_IMPLEMENTATION_CLASS_UID, VR_UI, FALSE, 0); } if(pElement) { pDS->SetConvertValue(pElement, LEAD_IMPLEMENTATION_CLASS_UID, 1); } // Implementation Version Name pElement = pDS->FindFirstElement(NULL, TAG_IMPLEMENTATION_VERSION_NAME, FALSE); if (pElement == NULL) { pElement = pDS->InsertElement(NULL, FALSE, TAG_IMPLEMENTATION_VERSION_NAME, VR_SH, FALSE, 0); } if(pElement) { pDS->SetConvertValue(pElement, LEAD_IMPLEMENTATION_VERSION_NAME , 1); } } void CCreateBasicVoiceAudioDlg::OnButtonCaptureAudio() { #ifdef NO_LEADTOOLS_MULTIMEDIA_SUPPORT AfxMessageBox("Sorry this feature is not available since the demo has been compiled without enabling LEADTOOLS Multimedia."); return; #else CCaptureWaveDialog CaptureWaveDialog; CString strInWaveFileName; GetDlgItemText (IDC_EDIT_INPUT_WAVE, strInWaveFileName); // Some sanity checks ! if((strInWaveFileName.GetLength() != 0) && (strInWaveFileName != DEFAULT_TEXT)) { CaptureWaveDialog.m_strFileName =strInWaveFileName; } else { CaptureWaveDialog.m_strFileName =""; } CWaitCursor Wait; if(CaptureWaveDialog.IsMMCapabilities()) { if (CaptureWaveDialog.DoModal() == IDOK) { if(CaptureWaveDialog.m_strFileName != "") { SetDlgItemText(IDC_EDIT_INPUT_WAVE,CaptureWaveDialog.m_strFileName); } } } else { AfxMessageBox(_T("Could not instantiate the capture library.\nPlease make sure that the \"LEADTOOLS Multimedia Toolkit\" is properly installed on this machine.")); } #endif }