bool CPattern::SetSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure) //------------------------------------------------------------------------------------ { if(rowsPerBeat < GetSoundFile().GetModSpecifications().patternRowsMin || rowsPerBeat > GetSoundFile().GetModSpecifications().patternRowsMax || rowsPerMeasure < rowsPerBeat || rowsPerMeasure > GetSoundFile().GetModSpecifications().patternRowsMax) { return false; } m_RowsPerBeat = rowsPerBeat; m_RowsPerMeasure = rowsPerMeasure; return true; }
void DeviceFrame::OnDeviceOpenSound(wxCommandEvent &) { wxString filename(GetSoundFile()); if (filename.empty()) { return; } audiere::SampleSourcePtr source = audiere::OpenSampleSource(wxString2CStr(filename)); if (!source) { wxMessageBox( wxT("Could not open source: ") + filename, wxT("Open Sound"), wxOK | wxCENTRE, this); return; } audiere::OutputStreamPtr stream = audiere::OpenSound(m_device, source); if (!stream) { wxMessageBox( wxT("Could not open sound: ") + filename, wxT("Open Sound"), wxOK | wxCENTRE, this); return; } // get the basename of the path for the window title wxString basename = wxFileNameFromPath(filename); new StreamFrame(this, wxT("Sound: ") + basename, stream.get(), source.get()); }
// Add or remove rows from the pattern. bool CPattern::Resize(const ROWINDEX newRowCount, bool enforceFormatLimits) //------------------------------------------------------------------------- { CSoundFile &sndFile = GetSoundFile(); ModCommand *newPattern; if(enforceFormatLimits) { const CModSpecifications& specs = sndFile.GetModSpecifications(); if(newRowCount > specs.patternRowsMax || newRowCount < specs.patternRowsMin) return false; } else { if(newRowCount > MAX_PATTERN_ROWS || newRowCount < 1) return false; } if(m_ModCommands == nullptr || newRowCount == m_Rows || (newPattern = AllocatePattern(newRowCount, GetNumChannels())) == nullptr) { return false; } // Copy over pattern data memcpy(newPattern, m_ModCommands, GetNumChannels() * std::min(m_Rows, newRowCount) * sizeof(ModCommand)); FreePattern(m_ModCommands); m_ModCommands = newPattern; m_Rows = newRowCount; return true; }
bool CPattern::Expand() //--------------------- { const ROWINDEX newRows = m_Rows * 2; const CHANNELINDEX nChns = GetNumChannels(); ModCommand *newPattern; if(!m_ModCommands || newRows > GetSoundFile().GetModSpecifications().patternRowsMax || (newPattern = AllocatePattern(newRows, nChns)) == nullptr) { return false; } for(ROWINDEX y = 0; y < m_Rows; y++) { memcpy(newPattern + y * 2 * nChns, m_ModCommands + y * nChns, nChns * sizeof(ModCommand)); } FreePattern(m_ModCommands); m_ModCommands = newPattern; m_Rows = newRows; return true; }
bool CPattern::Shrink() //--------------------- { if (!m_ModCommands || m_Rows < GetSoundFile().GetModSpecifications().patternRowsMin * 2) { return false; } m_Rows /= 2; const CHANNELINDEX nChns = GetNumChannels(); for(ROWINDEX y = 0; y < m_Rows; y++) { const PatternRow srcRow = GetRow(y * 2); const PatternRow nextSrcRow = GetRow(y * 2 + 1); PatternRow destRow = GetRow(y); for(CHANNELINDEX x = 0; x < nChns; x++) { const ModCommand &src = srcRow[x]; const ModCommand &srcNext = nextSrcRow[x]; ModCommand &dest = destRow[x]; dest = src; if(dest.note == NOTE_NONE && !dest.instr) { // Fill in data from next row if field is empty dest.note = srcNext.note; dest.instr = srcNext.instr; if(srcNext.volcmd != VOLCMD_NONE) { dest.volcmd = srcNext.volcmd; dest.vol = srcNext.vol; } if(dest.command == CMD_NONE) { dest.command = srcNext.command; dest.param = srcNext.param; } } } } return true; }
void DeviceFrame::DoOpenEffect(audiere::SoundEffectType type, wxString typestring) { wxString filename(GetSoundFile()); if (filename.empty()) { return; } audiere::SoundEffectPtr effect = audiere::OpenSoundEffect(m_device, wxString2CStr(filename), type); if (effect) { wxString basename = wxFileNameFromPath(filename); wxString title; title.sprintf(wxT("Sound Effect (%s): %s"), typestring.c_str(), basename.c_str()); new SoundEffectFrame(this, title, effect); } else { wxMessageBox( wxT("Could not open sound effect: ") + filename, wxT("Open Sound Effect"), wxOK | wxCENTRE, this); } }
void DeviceFrame::OnDeviceOpenStream(wxCommandEvent &) { wxString filename(GetSoundFile()); if (filename.empty()) { return; } #if wxUSE_UNICODE wxCharBuffer buffFilename = filename.mb_str(wxConvUTF8); audiere::SampleSourcePtr source = audiere::OpenSampleSource(buffFilename.data()); #else audiere::SampleSourcePtr source = audiere::OpenSampleSource(filename); #endif if (!source) { wxMessageBox( wxT("Could not open sample source: ") + filename, wxT("Open Stream"), wxOK | wxCENTRE, this); return; } audiere::LoopPointSourcePtr loop_source = audiere::CreateLoopPointSource(source); if (loop_source) { source = loop_source.get(); } audiere::OutputStreamPtr stream = audiere::OpenSound( m_device, source, true); if (!stream) { wxMessageBox( wxT("Could not open output stream: ") + filename, wxT("Open Stream"), wxOK | wxCENTRE, this); return; } // get the basename of the path for the window title wxString basename = wxFileNameFromPath(filename); new StreamFrame(this, wxT("Stream: ") + basename, stream.get(), source.get(), loop_source.get()); }
// Write some kind of effect data to the pattern. Exact data to be written and write behaviour can be found in the EffectWriter object. bool CPattern::WriteEffect(EffectWriter &settings) //------------------------------------------------ { // First, reject invalid parameters. if(!m_ModCommands || settings.m_row >= GetNumRows() || (settings.m_channel >= GetNumChannels() && settings.m_channel != CHANNELINDEX_INVALID)) { return false; } CHANNELINDEX scanChnMin = settings.m_channel, scanChnMax = settings.m_channel; // Scan all channels if(settings.m_channel == CHANNELINDEX_INVALID) { scanChnMin = 0; scanChnMax = GetNumChannels() - 1; } ModCommand * const baseCommand = GetpModCommand(settings.m_row, scanChnMin); ModCommand *m; // Scan channel(s) for same effect type - if an effect of the same type is already present, exit. if(!settings.m_allowMultiple) { m = baseCommand; for(CHANNELINDEX i = scanChnMin; i <= scanChnMax; i++, m++) { if(!settings.m_isVolEffect && m->command == settings.m_command) return true; if(settings.m_isVolEffect && m->volcmd == settings.m_command) return true; } } // Easy case: check if there's some space left to put the effect somewhere m = baseCommand; for(CHANNELINDEX i = scanChnMin; i <= scanChnMax; i++, m++) { if(!settings.m_isVolEffect && m->command == CMD_NONE) { m->command = settings.m_command; m->param = settings.m_param; return true; } if(settings.m_isVolEffect && m->volcmd == VOLCMD_NONE) { m->volcmd = settings.m_command; m->vol = settings.m_param; return true; } } // Ok, apparently there's no space. If we haven't tried already, try to map it to the volume column or effect column instead. if(settings.m_retry) { const bool isS3M = (GetSoundFile().GetType() & MOD_TYPE_S3M); // Move some effects that also work in the volume column, so there's place for our new effect. if(!settings.m_isVolEffect) { m = baseCommand; for(CHANNELINDEX i = scanChnMin; i <= scanChnMax; i++, m++) { switch(m->command) { case CMD_VOLUME: m->volcmd = VOLCMD_VOLUME; m->vol = m->param; m->command = settings.m_command; m->param = settings.m_param; return true; case CMD_PANNING8: if(isS3M && settings.m_param > 0x80) { break; } m->volcmd = VOLCMD_PANNING; m->command = settings.m_command; if(isS3M) { m->vol = m->param >> 1; } else { m->vol = (m->param >> 2) + 1; } m->param = settings.m_param; return true; } } }
CHANNELINDEX CPattern::GetNumChannels() const //------------------------------------------- { return GetSoundFile().GetNumChannels(); }